home *** CD-ROM | disk | FTP | other *** search
/ Aminet 39 / Aminet 39 (2000)(Schatztruhe)[!][Oct 2000].iso / Aminet / game / misc / WormWars.lha / wormwars / source / system.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-07  |  126.0 KB  |  3,769 lines

  1. /* $Filename: WormWars/Source/system.c $
  2.  * $VER:      Worm Wars 6.3 for Amiga $
  3.  *
  4.  * © Copyright 2000 James R. Jacobs. Freely distributable.
  5.  *        _
  6.  *       //        -=AMIGA=-
  7.  *      //
  8.  * _   //
  9.  * \\ //
  10.  *  \X/
  11.  
  12. #INCLUDES ---------------------------------------------------------------- */
  13.  
  14. #include "system.h"
  15.  
  16. #include "qdraw020.h"
  17.  
  18. #include <assert.h>
  19. // #define ASSERT
  20.  
  21. /* PROTOTYPES (Amiga-only) ----------------------------------------------- */
  22.  
  23. MODULE void freefx(void);
  24. MODULE void helpabout(void);
  25. MODULE void helploop(UBYTE type);
  26. MODULE void helpmanual(void);
  27. MODULE void loadthefx(void);
  28. MODULE void loadthemusic(void);
  29. MODULE void parsewb(void);
  30. MODULE void pausetimer(void);
  31. MODULE void unpausetimer(void);
  32.  
  33. MODULE void dot(SBYTE x, SBYTE y);
  34. MODULE void help(UBYTE type);
  35. MODULE void preserve(SWORD x, SBYTE row, SBYTE image, UWORD amount);
  36. MODULE void setpointer(SBYTE brush);
  37. MODULE void toggle(SBYTE key);
  38. MODULE void underline(SBYTE brush);
  39.  
  40. MODULE ABOOL beginfx(void);
  41. MODULE UBYTE ReadJoystick(UWORD joynum);
  42. MODULE SWORD xpixeltosquare(SWORD x);
  43. MODULE SWORD ypixeltosquare(SWORD y);
  44.  
  45. /* EXTERNAL VARIABLES (owned by engine.c, imported by system.c) ----------- */
  46.  
  47. IMPORT  struct ExecBase*        SysBase;
  48.  
  49. IMPORT  ABOOL                   clearthem, modified, randomflag;
  50. IMPORT  SBYTE                   a, eachworm[4][2][9],
  51.                                 level, levels, players, sourcelevel,
  52.                                 startx[MAXLEVELS + 1], starty[MAXLEVELS + 1];
  53. IMPORT  SWORD                   secondsleft, secondsperlevel;
  54. IMPORT  ULONG                   delay, r;
  55. IMPORT  UBYTE                   board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
  56.                                 field[FIELDX + 1][FIELDY + 1];
  57. IMPORT    struct HiScoreStruct    hiscore[HISCORES + 1];
  58. IMPORT    struct TeleportStruct    teleport[MAXLEVELS + 1][4];
  59. IMPORT    struct WormStruct       worm[4];
  60. IMPORT  TEXT                    pathname[81],
  61.                                 date[DATELENGTH + 1],
  62.                                 times[TIMELENGTH + 1];
  63.  
  64.         struct Library*         TimerBase;
  65.         struct ASLBase*         ASLBase        = NULL;
  66. //      struct Library*         AmigaGuideBase = NULL;
  67.         struct DiskFontBase*    DiskFontBase   = NULL;
  68.         struct GadToolsBase*    GadToolsBase   = NULL;
  69.         struct GfxBase*         GfxBase        = NULL;
  70.         struct Library*         IconBase       = NULL;
  71.         struct IntuitionBase*   IntuitionBase  = NULL;
  72.         struct MEDPlayerBase*   MEDPlayerBase  = NULL;
  73.         struct UtilityBase*     UtilityBase    = NULL;
  74.  
  75. /* MODULE VARIABLES (used only within system.c) --------------------------- */
  76.  
  77. MODULE  ABOOL  eversent[4],
  78.                icons        = TRUE,
  79.                ignore       = FALSE,
  80.                iso          = TRUE,
  81.                joy          = FALSE,
  82.                sticky       = FALSE;
  83. MODULE  SBYTE  AudioClosed  = TRUE,
  84.                brush        = STONE,
  85.                Controller   = GPCT_NOCONTROLLER,
  86.                JoyClosed    = TRUE,
  87.                OldPri       = 0,
  88.                TimerClosed  = TRUE;
  89. MODULE  UBYTE  fxable       = UNTRIED,
  90.                mode         = NULL,
  91.                musicable    = UNTRIED;
  92. MODULE    ULONG  fsize,
  93.                receipter[4] = {(ULONG) -1, (ULONG) -1, (ULONG) -1, (ULONG) -1};
  94. MODULE    UBYTE* fbase        = NULL;
  95. MODULE    BPTR   FilePtr      = NULL;
  96. MODULE  APTR   OldWindowPtr = NULL;
  97. MODULE    SWORD  pixy;
  98.  
  99. MODULE  struct QDPlaneInfo    QDPI;
  100. MODULE  ABOOL                 useqdraw            = FALSE;
  101.  
  102. MODULE    struct InputEvent     GameEvent;
  103. MODULE    struct TextAttr       WormWars8 =
  104. {    (STRPTR) "WormWars.font", 8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
  105. },                            Topaz8 =
  106. {    (STRPTR) "topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED
  107. };
  108.  
  109. MODULE    struct Gadget         *CheckboxGadgetPtr  = NULL,
  110.                               *CycleGadgetPtr[4]  = {NULL, NULL, NULL, NULL},
  111.                               *GListPtr           = NULL,
  112.                               *PrevGadgetPtr      = NULL,
  113.                               *RandomGadgetPtr    = NULL,
  114.                               *StringGadgetPtr[5] = {NULL, NULL, NULL, NULL, NULL};
  115. MODULE    struct MsgPort        *AudioPortPtr[4]    = {NULL, NULL, NULL, NULL},
  116.                               *JoyPortPtr         = NULL,
  117.                               *TimerPortPtr       = NULL;
  118. MODULE    struct timeval        *CurrentValPtr      = NULL,
  119.                               *PausedValPtr       = NULL,
  120.                               *StartValPtr        = NULL;
  121. MODULE    struct Window         *HelpWindowPtr      = NULL,
  122.                               *MainWindowPtr      = NULL;
  123.  
  124. MODULE  struct CIA*           CIAPtr              = (struct CIA *) 0xBFE001;
  125. MODULE    struct RDArgs*        ArgsPtr             = NULL;
  126. MODULE    struct FileRequester* ASLRqPtr            = NULL;
  127. MODULE    struct IOAudio*       AudioRqPtr[4]       = {NULL, NULL, NULL, NULL};
  128. MODULE    struct TextFont*      FontPtr             = NULL;
  129. MODULE    struct IOStdReq*      JoyRqPtr            = NULL;
  130. MODULE    struct Menu*          MenuPtr             = NULL;
  131. MODULE    struct Process*       ProcessPtr          = NULL;
  132. MODULE    struct Screen*        ScreenPtr           = NULL;
  133. MODULE    struct MMD0*          SongPtr             = NULL;
  134. MODULE    struct timerequest*   TimerRqPtr          = NULL;
  135. MODULE    struct VisualInfo*    VisualInfoPtr       = NULL;
  136. MODULE    struct WBArg*         WBArg               = NULL;
  137. MODULE    struct WBStartup*     WBMsg               = NULL;
  138.  
  139. /* FUNCTIONS -------------------------------------------------------------- */
  140.  
  141. int main(int argc, char** argv)
  142. {
  143. BPTR    OldDir;
  144. SLONG   i;
  145. ABOOL   success = FALSE;
  146. SBYTE   error = 0,
  147.         player, which;
  148. TEXT    saystring[SAYLIMIT + 1];
  149. SWORD   oldsecondsleft;
  150. UWORD   Pens[10] =
  151. {       BLACK,          /* DETAILPEN            text in title bar */
  152.         WHITE,          /* BLOCKPEN             fill title bar */
  153.         WHITE,          /* TEXTPEN              regular text on BACKGROUNDPEN */
  154.         LIGHTGREY,      /* SHINEPEN             bright edge */
  155.         DARKGREY,       /* SHADOWPEN            dark edge */
  156.         PURPLE,         /* FILLPEN              filling active window borders
  157.                                                 and selected gadgets */
  158.     BLACK,        /* FILLTEXTPEN        text rendered over FILLPEN */
  159.         BLACK,          /* BACKGROUNDPEN        background colour */
  160.         RED,            /* HIGHLIGHTTEXTPEN     highlighted text on BACKGROUNDPEN */
  161.         (UWORD) ~0      /* and used against BLOCKPEN in ASL save requesters */
  162. };
  163. SLONG                   args[11] = {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L};
  164. struct ColorSpec    Colours[21] =
  165. {   /* colour   red   green   blue   description */
  166.     {   0,      0x0,    0x0,    0x0},   /*        BLACK */
  167.     {   1,      0xF,    0xF,    0xF},   /*        WHITE */
  168.     {   2,      0x5,    0x5,    0x5},   /*    DARKGREY */
  169.     {   3,      0x8,    0x8,    0x8},   /*  MEDIUMGREY */
  170.     {   4,      0xB,    0xB,    0xB},   /*   LIGHTGREY */
  171.     {   5,      0x0,    0x0,    0x0},   /*        black */
  172.     {   6,      0xC,    0x5,    0xC},   /*        PURPLE */
  173.     {   7,      0x8,    0x4,    0x2},   /*        brown */
  174.     {   8,      0x3,    0x9,    0x3},   /*    DARKGREEN */
  175.     {   9,      0x4,    0xE,    0x4},   /*  light GREEN */
  176.     {   10,     0xF,    0x1,    0x1},   /*    DARKRED */
  177.     {   11,     0xF,    0x5,    0x5},   /*  light RED */
  178.     {   12,     0x3,    0x3,    0xF},   /*    DARKBLUE */
  179.     {   13,     0x6,    0x6,    0xF},   /*  light BLUE */
  180.     {   14,     0xA,    0xA,    0x2},   /*    DARKYELLOW */
  181.     {   15,     0xC,    0xC,    0x2},   /*  light YELLOW */
  182.     {   16,     0x0,    0x0,    0x0},   /* pointer: transparent */
  183.     {   17,     0xE,    0x4,    0x4},   /* pointer: fill */
  184.     {   18,     0x3,    0x3,    0x3},   /* pointer: shadow */
  185.     {   19,     0xC,    0xC,    0xC},   /* pointer: shine */
  186.     {   -1,     NULL,   NULL,   NULL}
  187. };
  188.  
  189. /* Start of program.
  190.  
  191. version embedding into executable */
  192.  
  193. if (0) /* that is, never */
  194.     say(VERSION, ANYTHING);
  195.  
  196. if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37L)))
  197. {    Write(Output(), OLDKICKSTART, strlen(OLDKICKSTART));
  198.     cleanexit(EXIT_FAILURE);
  199. }
  200.  
  201. /* From this point onwards, we can be sure we have Kickstart 2.04+... */
  202.  
  203. for (i = 0; i <= SAMPLES; i++)
  204.     samp[i].base = NULL;
  205. enginesetup();
  206. ProcessPtr = (struct Process *) FindTask(NULL);
  207.  
  208. if (SysBase->LibNode.lib_Version < 36L)
  209. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Need exec.library V36+!\0", 24);
  210.     cleanexit(EXIT_FAILURE);
  211. }
  212. if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L)))
  213. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open graphics.library!\0", 24);
  214.     cleanexit(EXIT_FAILURE);
  215. }
  216. if (!(GadToolsBase = (struct GadToolsBase *) OpenLibrary("gadtools.library", 37L)))
  217. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open GadTools.library V37+!\0", 24);
  218.     cleanexit(EXIT_FAILURE);
  219. }
  220. if (!(ASLBase = (struct ASLBase *) OpenLibrary("asl.library", 0L)))
  221. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open ASL.library!\0", 24);
  222.     cleanexit(EXIT_FAILURE);
  223. }
  224. if (!(UtilityBase = (struct UtilityBase *) OpenLibrary("utility.library", 0L)))
  225. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open utility.library!\0", 24);
  226.     cleanexit(EXIT_FAILURE);
  227. }
  228. if (!(IconBase = (struct Library *) OpenLibrary("icon.library", 0L)))
  229. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open icon.library!\0", 24);
  230.         cleanexit(EXIT_FAILURE);
  231. }
  232.  
  233. /* argument parsing */
  234.  
  235. if (argc) /* started from CLI */
  236. {   if (!(ArgsPtr = ReadArgs
  237.     (   "-F=NOFX/S,-M=NOMUSIC/S,-I=NOICONS/S,-P=PRI/K/N,-O=OVERHEAD/S,"
  238.         "-S=SHUFFLE/S,GREEN/K,RED/K,BLUE/K,YELLOW/K,FILE",
  239.         (LONG *) args,
  240.         NULL
  241.     )))
  242.     {   Printf
  243.         (   "Usage: %s [-f=NOFX] [-m=NOMUSIC] [-i=NOICONS] "
  244.             "[-p=PRI <priority>] [-o=OVERHEAD] [-s=SHUFFLE] "
  245.             "[GREEN=HUMAN|AMIGA|NONE] "
  246.             "[RED=HUMAN|AMIGA|NONE] [BLUE=HUMAN|AMIGA|NONE] "
  247.             "[YELLOW=HUMAN|AMIGA|NONE] [[FILE=]<fieldset>]\n",
  248.             argv[0]
  249.         );
  250.         cleanexit(EXIT_FAILURE);
  251.     }
  252.     if (args[0])
  253.         fxable = DEFER;
  254.     if (args[1])
  255.         musicable = DEFER;
  256.     if (args[2])
  257.         icons = FALSE;
  258.     if (args[3])
  259.     {    if (args[3] < -128 || args[3] > 5)
  260.            {   Printf("%s: Priority range is -128 to +5\n", argv[0]);
  261.                cleanexit(EXIT_FAILURE);
  262.          }
  263.         OldPri = SetTaskPri((struct Task *) ProcessPtr, args[3]);
  264.     }
  265.     if (args[4])
  266.         iso = FALSE;
  267.     if (args[5])
  268.             randomflag = TRUE;
  269.         if (args[6])
  270.     {    if (!stricmp(args[6], "HUMAN"))
  271.             worm[0].control = HUMAN;
  272.         elif (!stricmp(args[6], "AMIGA"))
  273.             worm[0].control = AMIGA;
  274.         elif (!stricmp(args[6], "NONE"))
  275.             worm[0].control = NONE;
  276.         else
  277.         {    Printf("%s: Green worm control must be HUMAN, AMIGA or NONE\n", argv[0]);
  278.             cleanexit(EXIT_FAILURE);
  279.     }    }
  280.     if (args[7])
  281.     {    if (!stricmp(args[7], "HUMAN"))
  282.             worm[1].control = HUMAN;
  283.         elif (!stricmp(args[7], "AMIGA"))
  284.             worm[1].control = AMIGA;
  285.         elif (!stricmp(args[7], "NONE"))
  286.             worm[1].control = NONE;
  287.         else
  288.         {    Printf("%s: Red worm control must be HUMAN, AMIGA or NONE\n", argv[0]);
  289.             cleanexit(EXIT_FAILURE);
  290.     }    }
  291.     if (args[8])
  292.     {    if (!stricmp(args[8], "HUMAN"))
  293.             worm[2].control = HUMAN;
  294.         elif (!stricmp(args[8], "AMIGA"))
  295.             worm[2].control = AMIGA;
  296.         elif (!stricmp(args[8], "NONE"))
  297.             worm[2].control = NONE;
  298.         else
  299.         {    Printf("%s: Blue worm control must be HUMAN, AMIGA or NONE\n", argv[0]);
  300.             cleanexit(EXIT_FAILURE);
  301.     }    }
  302.     if (args[9])
  303.     {    if (!stricmp(args[9], "HUMAN"))
  304.             worm[3].control = HUMAN;
  305.         elif (!stricmp(args[9], "AMIGA"))
  306.             worm[3].control = AMIGA;
  307.         elif (!stricmp(args[9], "NONE"))
  308.             worm[3].control = NONE;
  309.         else
  310.         {    Printf("%s: Yellow worm control must be HUMAN, AMIGA or NONE\n", argv[0]);
  311.             cleanexit(EXIT_FAILURE);
  312.     }    }
  313.     if (args[10])
  314.         strcpy(pathname, args[10]);
  315. }
  316. else /* started from WB */
  317. {    WBMsg = (struct WBStartup *) argv;
  318.     WBArg = WBMsg->sm_ArgList; /* head of the arg list */
  319.  
  320.     for (i = 0;
  321.          i < WBMsg->sm_NumArgs;
  322.          i++, WBArg++)
  323.     {    if (WBArg->wa_Lock)
  324.         {    /* something that does not support locks */
  325.             parsewb();
  326.         }
  327.         else
  328.         {    /* locks supported, change to the proper directory */
  329.             OldDir = CurrentDir(WBArg->wa_Lock);
  330.             parsewb();
  331.             CurrentDir(OldDir);
  332.                 }
  333.                 if (i == 1)
  334.                         strcpy(pathname, WBArg->wa_Name);
  335. }    }
  336.  
  337. if (!(DiskFontBase = (struct DiskFontBase *) OpenLibrary("diskfont.library", 0L)))
  338.     error = 1;
  339.     
  340. if
  341. (       (!(StartValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
  342. ||      (!(CurrentValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
  343. ||      (!(PausedValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
  344. )
  345. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't allocate timer value structure!\0", 24);
  346.     cleanexit(EXIT_FAILURE);
  347. }
  348. if (!(TimerPortPtr = (struct MsgPort *) CreateMsgPort()))
  349. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't allocate timer message port!\0", 24);
  350.     cleanexit(EXIT_FAILURE);
  351. }
  352. if (!(TimerRqPtr = (struct timerequest *) CreateIORequest(TimerPortPtr, sizeof(struct timerequest))))
  353. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create timer I/O request!\0", 24);
  354.     cleanexit(EXIT_FAILURE);
  355. }
  356. if (TimerClosed = OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerRqPtr, 0))
  357. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open timer.device!\0", 24);
  358.     cleanexit(EXIT_FAILURE);
  359. }
  360. TimerBase = (struct Library *) TimerRqPtr->tr_node.io_Device;
  361.  
  362. /* PREPARE DISPLAY -----------------------------------------------
  363.  
  364. font and screen */
  365.  
  366. if ((!error) && (FontPtr = (struct TextFont *) OpenDiskFont(&WormWars8)))
  367. {   /* loaded WormWars.font */
  368.  
  369.     ScreenPtr = (struct Screen *) OpenScreenTags
  370.     (   NULL,
  371.         SA_Width,       640,
  372.         SA_Height,      256,
  373.         SA_Depth,       DEPTH,
  374.         SA_DisplayID,   HIRES_KEY | PAL_MONITOR_ID,
  375.         SA_Title,       TITLEBAR,
  376.         SA_Colors,      Colours,
  377.         SA_Font,        &WormWars8,
  378.         SA_Pens,        Pens,
  379.         SA_PubName,     "WormWars",
  380.         TAG_DONE
  381.     );
  382.     if (!ScreenPtr)
  383.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open screen!\0", 24);
  384.         cleanexit(EXIT_FAILURE);
  385. }   }
  386. else
  387. {   if (!error)
  388.         error = 2;
  389.  
  390.     ScreenPtr = (struct Screen *) OpenScreenTags
  391.     (   NULL,
  392.         SA_Width,       640,
  393.         SA_Height,      256,
  394.         SA_Depth,       DEPTH,
  395.         SA_DisplayID,   HIRES_KEY | PAL_MONITOR_ID,
  396.         SA_Title,       TITLEBAR,
  397.         SA_Colors,      Colours,
  398.         SA_Font,        &Topaz8,
  399.         SA_Pens,        Pens,
  400.         SA_PubName,     "WormWars",
  401.         TAG_DONE
  402.     );
  403.     if (!ScreenPtr)
  404.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open screen nor font!\0", 24);
  405.         cleanexit(EXIT_FAILURE);
  406. }   }
  407.  
  408. PubScreenStatus(ScreenPtr, NULL); // take the screen public
  409.  
  410. /* For some reason, we lose 4 memory chunks around this point: 2 chunks
  411. each of 292 bytes and 10 bytes. It is related to OpenScreenTagList(),
  412. but is not related to the SA_Colors, SA_Font or SA_Pens tags, nor to
  413. the timer.device.
  414.  
  415. Now that the screen is set up, we initialize the turbo graphics as
  416. follows: */
  417.  
  418. for (i = 0; i < DEPTH; i++)
  419.     QDPI.pi_Planes[i] = ScreenPtr->RastPort.BitMap->Planes[i];
  420. QDPI.pi_BPR           = ScreenPtr->RastPort.BitMap->BytesPerRow;
  421. QDPI.pi_PlaneSZ       = ScreenPtr->RastPort.BitMap->BytesPerRow *
  422.                         ScreenPtr->RastPort.BitMap->Rows;
  423.  
  424. /* GetBitMapAttr() is more forwards-compatible than direct structure
  425. access. */
  426. useqdraw = (SysBase->AttnFlags & AFB_68020);
  427.  
  428. /* GadTools */
  429.  
  430. if (!(CycleGadget.ng_VisualInfo = StringGadget.ng_VisualInfo = CheckboxGadget.ng_VisualInfo = RandomGadget.ng_VisualInfo = VisualInfoPtr = (APTR) GetVisualInfo(ScreenPtr, TAG_DONE)))
  431. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't get GadTools visual info!\0", 24);
  432.     cleanexit(EXIT_FAILURE);
  433. }
  434. if (!(MenuPtr = (struct Menu *) CreateMenus(NewMenu, TAG_DONE)))
  435. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create menus!\0", 24);
  436.     cleanexit(EXIT_FAILURE);
  437. }
  438. if (!(LayoutMenus(MenuPtr, VisualInfoPtr, TAG_DONE)))
  439. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't lay out menus!\0", 24);
  440.     cleanexit(EXIT_FAILURE);
  441. }
  442. if (!(PrevGadgetPtr = (struct Gadget *) CreateContext(&GListPtr)))
  443. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create GadTools context!\0", 24);
  444.     cleanexit(EXIT_FAILURE);
  445. }
  446. for (player = 0; player <= 3; player++)
  447. {       CycleGadget.ng_TopEdge = TSOFFSET + 84 + (player * (FONTX + 8));
  448.     CycleGadget.ng_GadgetText = CycleText[player];
  449.     CycleGadgetPtr[player] = PrevGadgetPtr = (struct Gadget *) CreateGadget
  450.     (    CYCLE_KIND,
  451.         PrevGadgetPtr,
  452.         &CycleGadget,
  453.         GTCY_Labels, CycleOptions[player],
  454.         GTCY_Active, worm[player].control,
  455.         GT_Underscore, '_',
  456.         GA_Disabled, TRUE,
  457.         TAG_DONE
  458.     );
  459. }
  460. RandomGadgetPtr = PrevGadgetPtr = (struct Gadget *) CreateGadget
  461. (    CHECKBOX_KIND,
  462.     PrevGadgetPtr,
  463.     &RandomGadget,
  464.     GTCB_Checked, randomflag,
  465.     GT_Underscore, '_',
  466.     GA_Disabled, TRUE,
  467.     TAG_DONE
  468. );
  469. CheckboxGadgetPtr = PrevGadgetPtr = (struct Gadget *) CreateGadget
  470. (    CHECKBOX_KIND,
  471.     PrevGadgetPtr,
  472.     &CheckboxGadget,
  473.     GTCB_Checked, iso,
  474.     GT_Underscore, '_',
  475.     GA_Disabled, TRUE,
  476.     TAG_DONE
  477. );
  478.  
  479. /* main window */
  480.  
  481. if (!(MainWindowPtr = (struct Window *) OpenWindowTags(NULL,
  482.         WA_Top,                 11,
  483.         WA_Width,               SCREENXPIXEL,
  484.         WA_Height,              SCREENYPIXEL,
  485.         WA_IDCMP,               IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_CLOSEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MENUPICK | IDCMP_MENUVERIFY | CYCLEIDCMP | STRINGIDCMP | CHECKBOXIDCMP | IDCMP_REFRESHWINDOW | IDCMP_INTUITICKS,
  486.         WA_Gadgets,             GListPtr,
  487.     WA_CustomScreen,    ScreenPtr,
  488.     WA_Borderless,        TRUE,
  489.     WA_Activate,        TRUE,
  490.     WA_SmartRefresh,    TRUE,
  491.     WA_RptQueue,        16,
  492.     TAG_DONE)))
  493.     {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open main window!\0", 24);
  494.         cleanexit(EXIT_FAILURE);
  495.     }
  496.  
  497. /* redirection of AmigaDOS system requesters */
  498.     
  499. OldWindowPtr = ProcessPtr->pr_WindowPtr;
  500. ProcessPtr->pr_WindowPtr = (APTR) MainWindowPtr;
  501.  
  502. if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, PATTERN, ASL_Window, MainWindowPtr, TAG_DONE)))
  503. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create ASL request!\0", 24);
  504.     cleanexit(EXIT_FAILURE);
  505. }
  506.  
  507. /* String gadgets: first the window is opened with the cycle and
  508. checkbox gadgets.
  509.     It is necessary not to display the string gadgets yet, so the
  510. gadgets are then created and added to the gadget list. You will note
  511. there is no command given to render them as yet. When the attributes
  512. are modified at highscore time, the applicable gadget is refreshed
  513. then. */
  514.  
  515. for (which = 0; which <= HISCORES; which++)
  516. {       StringGadget.ng_TopEdge = TSOFFSET + (which * HISCOREDISTANCE);
  517.     StringGadgetPtr[which] = PrevGadgetPtr = (struct Gadget *) CreateGadget(STRING_KIND, PrevGadgetPtr, &StringGadget, GTST_MaxChars, NAMELENGTH, STRINGA_ReplaceMode, TRUE, GA_Disabled, TRUE, TAG_DONE);
  518. }
  519. if (!PrevGadgetPtr)
  520. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create GadTools gadgets!\0", 24);
  521.     cleanexit(EXIT_FAILURE);
  522. }
  523.  
  524. if (!icons)
  525.         NewMenu[CREATEICONS].nm_Flags &= ~CHECKED;
  526.  
  527. if (error == 1)
  528. {    say("Can't open diskfont.library!", RED);
  529.     anykey(TRUE);
  530. } else if (error == 2)
  531. {    say("Can't open WormWars.font!", RED);
  532.     anykey(TRUE);
  533. }
  534.  
  535. if (!(JoyPortPtr = (struct MsgPort *) CreateMsgPort()))
  536. {    say("Can't create joystick message port!", BLUE);
  537.     anykey(TRUE);
  538. } else if (!(JoyRqPtr = (struct IOStdReq *) CreateIORequest(JoyPortPtr, sizeof(struct IOStdReq))))
  539. {    say("Can't create joystick I/O request!", BLUE);
  540.     anykey(TRUE);
  541. } else if (JoyClosed = OpenDevice("gameport.device", 1, (struct IORequest *) JoyRqPtr, 0))
  542. {    say("Can't open gameport.device!", BLUE);
  543.     anykey(TRUE);
  544. } else
  545. {    Forbid();
  546.     JoyRqPtr->io_Command        = GPD_ASKCTYPE;
  547.     JoyRqPtr->io_Length            = 1;
  548.     JoyRqPtr->io_Flags            = IOF_QUICK;
  549.     JoyRqPtr->io_Data            = (APTR) &Controller;
  550.     DoIO((struct IORequest *) JoyRqPtr);
  551.     if (Controller == GPCT_NOCONTROLLER)
  552.     {    Controller                = GPCT_ABSJOYSTICK;
  553.         JoyRqPtr->io_Command    = GPD_SETCTYPE;
  554.         JoyRqPtr->io_Length     = 1;
  555.         JoyRqPtr->io_Data        = (APTR) &Controller;
  556.         DoIO((struct IORequest *) JoyRqPtr);
  557.         success = TRUE;
  558.     }
  559.     Permit();
  560.     /* Note that say(), anykey() calls must be outside the
  561.     Forbid()/Permit() pair. */
  562.     if (success)
  563.     {    JoyRqPtr->io_Command    = GPD_SETTRIGGER;
  564.         JoyRqPtr->io_Data        = (APTR) &Trigger;
  565.         JoyRqPtr->io_Length        = sizeof(struct GamePortTrigger);
  566.         DoIO((struct IORequest *) JoyRqPtr);
  567.         sendreadrequest();
  568.         joy = TRUE;
  569.     } else
  570.     {    say("Gameport already in use!", BLUE);
  571.         anykey(TRUE);
  572. }    }
  573.  
  574. if (musicable == UNTRIED)
  575.     loadthemusic();
  576. if (fxable == UNTRIED)
  577.     loadthefx();
  578.  
  579. if (fxable == SUCCEEDED)
  580.     toggle(F);
  581. else if (musicable == SUCCEEDED)
  582.     toggle(M);
  583.  
  584. strcpy(saystring, "Loading ");
  585. strcat(saystring, pathname);
  586. strcat(saystring, "...");
  587. say(saystring, WHITE);
  588. if (loadfields(pathname))
  589. {    strcpy(saystring, "Can't open ");
  590.     strcat(saystring, pathname);
  591.     strcat(saystring, "!");
  592.     say(saystring, RED);
  593.         newfields();
  594.     anykey(TRUE);
  595. }
  596.  
  597. while (1)
  598. {   titlescreen();
  599.  
  600.     /* MAIN GAME LOOP ------------------------------------------------- */
  601.  
  602.     while (a == PLAYGAME)
  603.     {   r++;
  604.         oldsecondsleft = secondsleft;
  605.         GetSysTime(CurrentValPtr);
  606.         SubTime(CurrentValPtr, StartValPtr);
  607.         secondsleft = secondsperlevel - CurrentValPtr->tv_secs;
  608.         if (secondsleft != oldsecondsleft)
  609.             timeloop();
  610.         TimerRqPtr->tr_node.io_Command  = TR_ADDREQUEST;
  611.         TimerRqPtr->tr_time.tv_secs     = 0;
  612.         TimerRqPtr->tr_time.tv_micro    = delay;
  613.         SendIO((struct IORequest *) TimerRqPtr);
  614.         gameloop();
  615.         // CheckIO() returns FALSE if complete, pointer if incomplete.
  616.         if (CheckIO((struct IORequest *) TimerRqPtr)) // CheckIO returns pointer to struct IORequest
  617.             draw(CLOCKICON, ICONY, CLOCK);
  618.         else draw(CLOCKICON, ICONY, BLACKENED);
  619.         WaitIO((struct IORequest *) TimerRqPtr);
  620.     }
  621.     say("Title Screen", WHITE);
  622. }
  623. }
  624.  
  625. /* SUPPORT FUNCTIONS ----------------------------------------------------- */
  626.  
  627. /* NAME     anykey -- wait for a user press
  628. SYNOPSIS    anykey(ABOOL);
  629. FUNCTION    Waits for a user response. Optional automatic timeout.
  630. INPUTS      timeout - timeout?
  631. RESULTS     FALSE if user presses Escape, TRUE otherwise.
  632. FILE        system.c */
  633.  
  634. ABOOL anykey(ABOOL timeout)
  635. {    ABOOL                    done        = FALSE;
  636.     SBYTE                    count        = 0;
  637.     UWORD                    code, qual;
  638.     ULONG                    class;
  639.     struct IntuiMessage*    MsgPtr;
  640.  
  641.     clearkybd();
  642.     Forbid();
  643.     MainWindowPtr->Flags |= WFLG_RMBTRAP;
  644.     Permit();
  645.     
  646.     while (!done)
  647.     {    if (joy && GetMsg(JoyPortPtr))
  648.         {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  649.                 done = TRUE;
  650.             sendreadrequest();
  651.         }
  652.         if (joy)
  653.         {    Wait((1L << MainWindowPtr->UserPort->mp_SigBit) | (1L << JoyPortPtr->mp_SigBit));
  654.             while (GetMsg(JoyPortPtr))
  655.             {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  656.                     done = TRUE;
  657.                 sendreadrequest();
  658.         }    }
  659.         else Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  660.         while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  661.         {    class = MsgPtr->Class;
  662.             code  = MsgPtr->Code;
  663.             qual  = MsgPtr->Qualifier;
  664.             GT_ReplyIMsg(MsgPtr);
  665.             switch(class)
  666.             {
  667.             case IDCMP_RAWKEY:
  668.                             if ((!(qual & IEQUALIFIER_REPEAT)) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
  669.                             {   done = TRUE;
  670.                                 if (code == M)
  671.                                     toggle(M);
  672.                                 else if (code == F)
  673.                                     toggle(F);
  674.                                 else if (code == ESCAPE)
  675.                                 {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  676.                                         if (verify())
  677.                                             cleanexit(EXIT_SUCCESS);
  678.                                     else
  679.                                     {   Forbid();
  680.                                         MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  681.                                         Permit();
  682.                                         return FALSE;
  683.                             }   }   }
  684.                         break;
  685.             case IDCMP_CLOSEWINDOW:
  686.                 cleanexit(EXIT_SUCCESS);
  687.                 break;
  688.             case IDCMP_ACTIVEWINDOW:
  689.                 ignore = TRUE;
  690.                 break;
  691.             case IDCMP_MOUSEBUTTONS:
  692.                 if ((code == SELECTDOWN || code == MENUDOWN) && !(qual & IEQUALIFIER_REPEAT))
  693.                     if (ignore)
  694.                         ignore = FALSE;
  695.                     else done = TRUE;
  696.                 break;
  697.             case IDCMP_INTUITICKS:
  698.                 if (timeout && ++count > PATIENCE)
  699.                     done = TRUE;
  700.                 break;
  701.             default:
  702.                 break;
  703.     }    }    }
  704.  
  705.     Forbid();
  706.     MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  707.     Permit();
  708.     return TRUE;
  709. }
  710.  
  711. void celebrate(void)
  712. {    ABOOL                    done = FALSE;
  713.     ULONG                    class;
  714.     UWORD                    code, qual;
  715.     struct IntuiMessage*    MsgPtr;
  716.     UBYTE                   player;
  717.  
  718.     for (player = 0; player <= 3; player++)
  719.         if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  720.              worm[player].hiscore = worm[player].score;
  721.     waitasec();
  722.     clearkybd();
  723.     while (!done)
  724.     {    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  725.         {    class = MsgPtr->Class;
  726.             code  = MsgPtr->Code;
  727.             qual  = MsgPtr->Qualifier;
  728.             GT_ReplyIMsg(MsgPtr);
  729.             switch (class)
  730.             {
  731.             case IDCMP_RAWKEY:
  732.                 if (code == ESCAPE)
  733.                 {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  734.                     {    if (verify())
  735.                             cleanexit(EXIT_SUCCESS);
  736.                     } else
  737.                         done = TRUE;
  738.                 }
  739.                 else if (code == RETURN || code == ENTER || code == SPACEBAR)
  740.                     done = TRUE;
  741.                 else if (code == M)
  742.                     toggle(M);
  743.                 else if (code == F)
  744.                     toggle(F);
  745.                 break;
  746.             case IDCMP_MOUSEBUTTONS:
  747.                 if (code == SELECTDOWN && !(qual & IEQUALIFIER_REPEAT))
  748.                     if (ignore)
  749.                         ignore = FALSE;
  750.                     else done = TRUE;
  751.                 break;
  752.             case IDCMP_ACTIVEWINDOW:
  753.                 ignore = TRUE;
  754.                 break;
  755.             case IDCMP_CLOSEWINDOW:
  756.                 cleanexit(EXIT_SUCCESS);
  757.                 break;
  758.             default:
  759.                 break;
  760.         }    }
  761.         if (joy && GetMsg(JoyPortPtr))
  762.         {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  763.                 done = TRUE;
  764.             sendreadrequest();
  765.         }
  766.         SetRGB4(&ScreenPtr->ViewPort, 17, rand() % 16, rand() % 16, rand() % 16);
  767.         draw(rand() % (FIELDX + 1), rand() % (FIELDY + 1), rand() % LASTOBJECT);
  768.     }
  769.     SetRGB4(&ScreenPtr->ViewPort, 17, 14, 4, 4);
  770.     a = GAMEOVER;
  771. }
  772.  
  773. void cleanexit(SLONG rc)
  774. {   SBYTE i;
  775.     struct Message* MsgPtr;
  776.  
  777. // CheckIO() returns NULL if complete, pointer if incomplete?
  778. if (TimerRqPtr && (!CheckIO((struct IORequest *) TimerRqPtr)))
  779.                         {       AbortIO((struct IORequest *) TimerRqPtr);
  780.                                 WaitIO((struct IORequest *) TimerRqPtr);
  781.                         }
  782.                                 freefx();
  783.                                 for (i = 0; i <= SAMPLES; i++)
  784.                                     if (samp[i].base)
  785.                                         FreeMem(samp[i].base, samp[i].size);
  786. if (mode == MUSIC)        StopPlayer();
  787. if (SongPtr)            UnLoadModule(SongPtr);
  788. if (MEDPlayerBase)    {    FreePlayer();
  789.                                 CloseLibrary((struct Library *) MEDPlayerBase);
  790.                         }
  791. if (joy)                {       AbortIO((struct IORequest *) JoyRqPtr);
  792.                                 WaitIO((struct IORequest *) JoyRqPtr);
  793.                         }
  794. if (Controller != GPCT_NOCONTROLLER)
  795.                         {       Forbid();
  796.                                 Controller           = GPCT_NOCONTROLLER;
  797.                                 JoyRqPtr->io_Command = GPD_SETCTYPE;
  798.                                 JoyRqPtr->io_Length  = 1;
  799.                                 JoyRqPtr->io_Data    = (APTR) &Controller;
  800.                                 DoIO((struct IORequest *) JoyRqPtr);
  801.                                 Permit();
  802.                         }
  803. if (!JoyClosed)                 CloseDevice((struct IORequest *) JoyRqPtr);
  804. if (JoyRqPtr)           {       DeleteIORequest((struct IORequest *) JoyRqPtr);
  805.                                 while(MsgPtr = GetMsg(JoyPortPtr))
  806.                                     ReplyMsg(MsgPtr); // important, or we lose memory
  807.                         }
  808. if (JoyPortPtr)            DeleteMsgPort(JoyPortPtr);
  809.  
  810. if (ASLRqPtr)            FreeAslRequest(ASLRqPtr);
  811. if (OldWindowPtr)        ProcessPtr->pr_WindowPtr = OldWindowPtr;
  812. if (MainWindowPtr)    {    clearkybd();
  813.                                 ClearMenuStrip(MainWindowPtr);
  814.                                 CloseWindow(MainWindowPtr);                                             }
  815. if (GListPtr)            FreeGadgets(GListPtr);
  816. if (MenuPtr)            FreeMenus(MenuPtr);
  817. if (VisualInfoPtr)        FreeVisualInfo(VisualInfoPtr);
  818. if (ScreenPtr)            CloseScreen(ScreenPtr);
  819. if (FontPtr)            CloseFont(FontPtr);
  820. if (!TimerClosed)               CloseDevice((struct IORequest *) TimerRqPtr);
  821. if (TimerRqPtr)                 DeleteIORequest(TimerRqPtr);
  822. if (TimerPortPtr)        DeleteMsgPort(TimerPortPtr);
  823. if (PausedValPtr)        FreeMem(PausedValPtr, sizeof(struct timeval));
  824. if (CurrentValPtr)        FreeMem(CurrentValPtr, sizeof(struct timeval));
  825. if (StartValPtr)        FreeMem(StartValPtr, sizeof(struct timeval));
  826. if (DiskFontBase)        CloseLibrary((struct Library *) DiskFontBase);
  827. if (UtilityBase)        CloseLibrary((struct Library *) UtilityBase);
  828. if (ASLBase)            CloseLibrary((struct Library *) ASLBase);
  829. if (GadToolsBase)        CloseLibrary((struct Library *) GadToolsBase);
  830. if (GfxBase)            CloseLibrary((struct Library *) GfxBase);
  831. if (IconBase)            CloseLibrary((struct Library *) IconBase);
  832. if (IntuitionBase)    {    OpenWorkBench();
  833.                                 CloseLibrary((struct Library *) IntuitionBase);                                    }
  834.                                 SetTaskPri((struct Task *) ProcessPtr, OldPri);
  835. if (ArgsPtr)            FreeArgs(ArgsPtr);
  836.                                 exit(rc); /* End of program. */
  837. }
  838.  
  839. void clearjoystick(void)
  840. {    if (joy)
  841.         while (GetMsg(JoyPortPtr))
  842.             sendreadrequest();
  843. }
  844.  
  845. void clearkybd(void)
  846. {    struct IntuiMessage* MsgPtr;
  847.  
  848.     while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  849.         GT_ReplyIMsg(MsgPtr);
  850. }
  851.  
  852. void draw(SBYTE x, SBYTE y, UBYTE image)
  853. {   SWORD pixx;
  854.  
  855.     /* Isometric methodology:
  856.     
  857.     read the colour of the pixel, then set the colour in the image
  858.     to the same value.
  859.  
  860.     So if, for the top left pixel, we read colour 10 (= $A or %1010),
  861.     we have to clear the relevant bits in plane 0 and 2, and set them
  862.     in planes 1 and 3.
  863.  
  864.     plane 0 (least significant bit)
  865.         1234567890123456 pixels for top row (y = 0)
  866.         1234567890123456 pixels for next row (y = 1)
  867.         : : :
  868.     plane 1
  869.         : : :
  870.  
  871.      01234567890
  872.     0..#########
  873.     1..#########
  874.     2.#########.
  875.     3.#########.
  876.     4#########..
  877.     5#########..
  878.  
  879.     Image is effectively 9*6, but requires an 11*6 bitmap. */
  880.  
  881.     if (a == PLAYGAME && iso)
  882.     {   pixx = (x * ISOSQUAREX) + 20 + ((FIELDY - y) * 3);
  883.         pixy = (y * ISOSQUAREY) + STARTYPIXEL;
  884.  
  885.         if (useqdraw)
  886.         {   // Turbo field rendering routines, thanks to Jilles Tjoelker.
  887.             qdraw020iso
  888.             (   &QDPI,
  889.                 pixx,
  890.                 pixy + MainWindowPtr->TopEdge,
  891.                 (WORD *) IsoImageData[image]
  892.             );
  893.         }
  894.         else
  895.         {   IsoImage.ImageData = IsoImageData[image];
  896.             preserve(pixx,      0, image, 32768);
  897.             preserve(pixx,      1, image, 32768);
  898.             preserve(pixx,      2, image, 32768);
  899.             preserve(pixx,      3, image, 32768);
  900.             preserve(pixx +  1, 0, image, 16384);
  901.             preserve(pixx +  1, 1, image, 16384);
  902.             preserve(pixx +  9, 4, image,    64);
  903.             preserve(pixx +  9, 5, image,    64);
  904.             preserve(pixx + 10, 2, image,    32);
  905.             preserve(pixx + 10, 3, image,    32);
  906.             preserve(pixx + 10, 4, image,    32);
  907.             preserve(pixx + 10, 5, image,    32);
  908.             DrawImage
  909.             (   MainWindowPtr->RPort,
  910.                 &IsoImage,
  911.                 pixx,
  912.                 pixy
  913.             );
  914.     }   }
  915.     else
  916.     {   if (useqdraw)
  917.         {   // Turbo field rendering routines, thanks to Jilles Tjoelker.
  918.             qdraw020
  919.             (   &QDPI,
  920.                 STARTXPIXEL + (SQUAREX * x),
  921.                 STARTYPIXEL + (SQUAREY * y) + MainWindowPtr->TopEdge,
  922.                 (WORD *) ImageData[image]
  923.             );
  924.         }
  925.         else
  926.         {   Image.ImageData = ImageData[image];
  927.             DrawImage
  928.             (   MainWindowPtr->RPort,
  929.                 &Image,
  930.                 STARTXPIXEL + (SQUAREX * x),
  931.                 STARTYPIXEL + (SQUAREY * y)
  932.             );
  933. }   }   }
  934.  
  935. MODULE void preserve(SWORD x, SBYTE row, SBYTE image, UWORD amount)
  936. {    LONG colour;
  937.     
  938.     /* x = image top-left corner coordinate on destination screen.
  939.     row = y-row of the image.
  940.     image = image number
  941.     amount = value of the bit to be set/cleared. */
  942.  
  943.     colour = ReadPixel
  944.     (    MainWindowPtr->RPort,
  945.         x,
  946.         pixy + row
  947.     );
  948.     if (colour & 8)
  949.         IsoImageData[image][row + 18] |= amount;
  950.     else IsoImageData[image][row + 18] &= ~amount;
  951.     if (colour & 4)
  952.         IsoImageData[image][row + 12] |= amount;
  953.     else IsoImageData[image][row + 12] &= ~amount;
  954.     if (colour & 2)
  955.         IsoImageData[image][row + 6] |= amount;
  956.     else IsoImageData[image][row + 6] &= ~amount;
  957.     if (colour & 1)
  958.         IsoImageData[image][row] |= amount;
  959.     else IsoImageData[image][row] &= ~amount;
  960. }
  961.  
  962. void effect(SBYTE index)
  963. {           SBYTE    i;
  964.             SBYTE    ok                = -1;
  965.             ULONG   oldestreceipt    = (ULONG) -1L;
  966.     PERSIST    ULONG   nextreceipt            = 1L;
  967.  
  968.     /* oldestreceipt = temporary variable for ascertaining oldest
  969.     sound still playing.
  970.     nextreceipt = next unused receipt number (monotonically incrementing). */
  971.  
  972.     if (mode == FX)
  973.     {    for (i = 0; i <= 3; i++)
  974.         {    /* decide on a channel */
  975.  
  976.             if (ok == -1)
  977.             {    if (!eversent[i])
  978.                     ok = i;
  979.                                 // CheckIO() returns NULL if complete, pointer if incomplete.
  980.                                 elif (CheckIO((struct IORequest *) AudioRqPtr[i]))
  981.                 {    WaitIO((struct IORequest *) AudioRqPtr[i]);
  982.                     ok = i;
  983.         }    }    }
  984.         if (ok == -1)
  985.         {   for (i = 0; i <= 3; i++)
  986.                 if (receipter[i] < oldestreceipt)
  987.                 {   ok = i;
  988.                     oldestreceipt = receipter[i];
  989.                 }
  990.             AbortIO((struct IORequest *) AudioRqPtr[ok]);
  991.             WaitIO((struct IORequest *) AudioRqPtr[ok]);
  992.         }
  993.         eversent[ok] = TRUE;
  994.         AudioRqPtr[ok]->ioa_Cycles              = 1;
  995.         AudioRqPtr[ok]->ioa_Request.io_Command  = CMD_WRITE;
  996.         AudioRqPtr[ok]->ioa_Request.io_Flags    = ADIOF_PERVOL;
  997.         AudioRqPtr[ok]->ioa_Request.io_Unit     = (struct Unit *) (1 << ok);
  998.         AudioRqPtr[ok]->ioa_Volume              = samp[index].volume;
  999.         AudioRqPtr[ok]->ioa_Period              = (UWORD) samp[index].speed;
  1000.         AudioRqPtr[ok]->ioa_Request.io_Message.mn_ReplyPort
  1001.                                                 = AudioPortPtr[ok];
  1002.         AudioRqPtr[ok]->ioa_Data                = (UBYTE *) samp[index].base;
  1003.         AudioRqPtr[ok]->ioa_Length              = samp[index].length[samp[index].bank];
  1004.         BeginIO(AudioRqPtr[ok]);
  1005.         receipter[ok] = nextreceipt;
  1006. }   }
  1007.  
  1008. void fieldedit(void)
  1009. {   AUTO    ABOOL                leftdown = FALSE, rightdown = FALSE,
  1010.                                  timer = FALSE;
  1011.     AUTO    UBYTE                oldbrush = ANYTHING, stamp;
  1012.     AUTO    SBYTE                deltax = 0, deltay = 0, lastx, lasty,
  1013.                                  pointerx, pointery, which, x, y;
  1014.     AUTO    UWORD                code, qual;
  1015.     AUTO    ULONG                class;
  1016.     AUTO    struct IntuiMessage* MsgPtr;
  1017.     AUTO    struct MenuItem*     ItemPtr;
  1018.     PERSIST ABOOL                clipboarded = FALSE;
  1019.     PERSIST UBYTE                clipboard[FIELDX + 1][FIELDY + 1];
  1020.  
  1021. say("Field Editor", WHITE);
  1022. setpointer(brush);
  1023. if (level > levels)
  1024.     level = levels;
  1025. OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, NOITEM, NOSUB));
  1026. if (!clipboarded)
  1027.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));
  1028.  
  1029. /* draw pseudo-gadgets */
  1030.  
  1031. clearscreen();
  1032. for (which = 0; which <= 8; which++)
  1033.     DrawBevelBox(MainWindowPtr->RPort, STARTXPIXEL - 5 - (SQUAREX * 3), 40 + STARTYPIXEL + (which * SQUAREY * 3), SQUAREX + 9, SQUAREY + 4, GT_VisualInfo, VisualInfoPtr);
  1034. SetAPen(MainWindowPtr->RPort, WHITE);
  1035. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (  GOLDGADGET * SQUAREY));
  1036. Text(MainWindowPtr->RPort, "F1:", 3);
  1037. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (SILVERGADGET * SQUAREY));
  1038. Text(MainWindowPtr->RPort, "F2:", 3);
  1039. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + ( EMPTYGADGET * SQUAREY));
  1040. Text(MainWindowPtr->RPort, "F3:", 3);
  1041. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (  WOODGADGET * SQUAREY));
  1042. Text(MainWindowPtr->RPort, "F4:", 3);
  1043. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + ( STONEGADGET * SQUAREY));
  1044. Text(MainWindowPtr->RPort, "F5:", 3);
  1045. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + ( METALGADGET * SQUAREY));
  1046. Text(MainWindowPtr->RPort, "F6:", 3);
  1047. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (   ONEGADGET * SQUAREY));
  1048. Text(MainWindowPtr->RPort, "F7:", 3);
  1049. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (   TWOGADGET * SQUAREY));
  1050. Text(MainWindowPtr->RPort, "F8:", 3);
  1051. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + ( STARTGADGET * SQUAREY));
  1052. Text(MainWindowPtr->RPort, "F9:", 3);
  1053. draw(GADGETX,   GOLDGADGET,   GOLD);
  1054. draw(GADGETX, SILVERGADGET, SILVER);
  1055. draw(GADGETX,  EMPTYGADGET,  EMPTY);
  1056. draw(GADGETX,   WOODGADGET,   WOOD);
  1057. draw(GADGETX,  STONEGADGET,  STONE);
  1058. draw(GADGETX,  METALGADGET,  METAL);
  1059. draw(GADGETX,    ONEGADGET,    ONE);
  1060. draw(GADGETX,    TWOGADGET,    TWO);
  1061. draw(GADGETX,  STARTGADGET,  START);
  1062. SetAPen(MainWindowPtr->RPort, BLACK);
  1063. RectFill
  1064. (    MainWindowPtr->RPort,
  1065.     STARTXPIXEL - SQUAREX - 1,
  1066.     UNDERLINEOFFSET - 1,
  1067.     STARTXPIXEL - SQUAREX + 3,
  1068.     UNDERLINEOFFSET + 4 + (SQUAREY * 25)
  1069. );
  1070. underline(brush);
  1071.  
  1072. turborender();
  1073. saylevel(WHITE);
  1074. clearkybd();
  1075. x = lastx = startx[level];
  1076. y = lasty = starty[level];
  1077.     
  1078. while (a == FIELDEDIT)
  1079. {    stamp = NOSQUARE;
  1080.  
  1081.         Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  1082.         while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  1083.     {    class = MsgPtr->Class;
  1084.         code  = MsgPtr->Code;
  1085.         qual  = MsgPtr->Qualifier;
  1086.         if (class == IDCMP_MENUVERIFY && MsgPtr->MouseX >= STARTXPIXEL && MsgPtr->MouseX <= ENDXPIXEL && MsgPtr->MouseY >= STARTYPIXEL && MsgPtr->MouseY <= ENDYPIXEL)
  1087.         {    MsgPtr->Code = MENUCANCEL;
  1088.             oldbrush = brush;
  1089.             brush = EMPTY;
  1090.             rightdown = TRUE;
  1091.         }
  1092.         ReplyMsg((struct Message *) MsgPtr);
  1093.         switch (class)
  1094.         {
  1095.         case IDCMP_MENUPICK:
  1096.             while (code != MENUNULL)
  1097.             {    ItemPtr = ItemAddress(MenuPtr, code);
  1098.                 switch (MENUNUM(code))
  1099.                 {
  1100.                 case MN_PROJECT:
  1101.                     switch (ITEMNUM(code))
  1102.                     {
  1103.                     case IN_NEW:
  1104.                         effect(FXFILENEW);
  1105.                         newfields();
  1106.                         say("New done.", WHITE);
  1107.                     break;
  1108.                     case IN_OPEN:
  1109.                         effect(FXFILEOPEN);
  1110.                         fileopen(FALSE);
  1111.                     break;
  1112.                     case IN_REVERT:
  1113.                         fileopen(TRUE);
  1114.                     break;
  1115.                     case IN_SAVE:
  1116.                         effect(FXFILESAVE);
  1117.                         if (modified)
  1118.                         {    clearhiscores();
  1119.                             modified = FALSE;
  1120.                         }
  1121.                         filesaveas(FALSE);
  1122.                         break;
  1123.                     case IN_SAVEAS:
  1124.                         effect(FXFILESAVEAS);
  1125.                         if (modified)
  1126.                         {    clearhiscores();
  1127.                             modified = FALSE;
  1128.                         }
  1129.                         filesaveas(TRUE);
  1130.                         break;
  1131.                     case IN_QUIT:
  1132.                         if (verify())
  1133.                             cleanexit(EXIT_SUCCESS);
  1134.                         break;
  1135.                     default:
  1136.                         break;
  1137.                     }
  1138.                     break;
  1139.                 case MN_EDIT:
  1140.                     switch (ITEMNUM(code))
  1141.                     {
  1142.                     case IN_CUT:
  1143.                         effect(FXEDITCUT);
  1144.                         for (x = 0; x <= FIELDX; x++)
  1145.                             for (y = 0; y <= FIELDY; y++)
  1146.                                 clipboard[x][y] = board[level][x][y];
  1147.                         leveldelete();
  1148.                         clipboarded = TRUE;
  1149.                         modified = TRUE;
  1150.                         OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));
  1151.                     break;
  1152.                     case IN_COPY:
  1153.                         effect(FXEDITCOPY);
  1154.                         for (x = 0; x <= FIELDX; x++)
  1155.                             for (y = 0; y <= FIELDY; y++)
  1156.                                 clipboard[x][y] = board[level][x][y];
  1157.                         clipboarded = TRUE;
  1158.                         OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));
  1159.                     break;
  1160.                     case IN_PASTE:
  1161.                         effect(FXEDITPASTE);
  1162.                         for (x = 0; x <= FIELDX; x++)
  1163.                             for (y = 0; y <= FIELDY; y++)
  1164.                                 board[level][x][y] = clipboard[x][y];
  1165.                         turborender();
  1166.                         modified = TRUE;
  1167.                     break;
  1168.                     case IN_ERASE:
  1169.                         levelerase();
  1170.                     break;
  1171.                     case IN_INSERT:
  1172.                         levelinsert();
  1173.                     break;
  1174.                     case IN_DELETE:
  1175.                                                 effect(FXEDITDELETE);
  1176.                         leveldelete();
  1177.                     break;
  1178.                     case IN_APPEND:
  1179.                         levelappend();
  1180.                     break;
  1181.                     default:
  1182.                     break;
  1183.                     }
  1184.                 break;
  1185.                 case MN_SETTINGS:
  1186.                     switch(ITEMNUM(code))
  1187.                     {
  1188.                     case IN_CREATEICONS:
  1189.                         if (ItemPtr->Flags & CHECKED)
  1190.                             icons = TRUE;
  1191.                         else icons = FALSE;
  1192.                     break;
  1193.                     default:
  1194.                     break;
  1195.                     }
  1196.                 break;
  1197.                 case MN_HELP:
  1198.                     switch(ITEMNUM(code))
  1199.                     {
  1200.                     case IN_CREATURES:
  1201.                         help(ORB);
  1202.                     break;
  1203.                     case IN_OBJECTS:
  1204.                         help(AFFIXER);
  1205.                     break;
  1206.                     case IN_MANUAL:
  1207.                         helpmanual();
  1208.                     break;
  1209.                     case IN_ABOUT:
  1210.                         helpabout();
  1211.                     break;
  1212.                     default:
  1213.                     break;
  1214.                     }
  1215.                 break;
  1216.                 default:
  1217.                 break;
  1218.                 }
  1219.                 code = ItemPtr->NextSelect;
  1220.             }
  1221.             break;
  1222.             case IDCMP_RAWKEY:
  1223.                 lastx = x;
  1224.                 lasty = y;
  1225.             switch(code)
  1226.             {
  1227.             case DELETE:
  1228.                 if (!(qual & IEQUALIFIER_REPEAT))
  1229.                 {    effect(FXCLICK);
  1230.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1231.                         level = 1;
  1232.                     else if (--level < 0)
  1233.                         level = levels;
  1234.                     saylevel(WHITE);
  1235.                     turborender();
  1236.                 }
  1237.                 break;
  1238.             case HELP:
  1239.                 if (!(qual & IEQUALIFIER_REPEAT))
  1240.                 {    effect(FXCLICK);
  1241.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1242.                         level = levels;
  1243.                     else if (++level > levels)
  1244.                         level = 0;
  1245.                     saylevel(WHITE);
  1246.                     turborender();
  1247.                 }
  1248.                 break;
  1249.             case M:
  1250.                 if (!(qual & IEQUALIFIER_REPEAT))
  1251.                     toggle(M);
  1252.                 break;
  1253.             case F:
  1254.                 if (!(qual & IEQUALIFIER_REPEAT))
  1255.                     toggle(F);
  1256.                 break;
  1257.             case ESCAPE:
  1258.                 if (!(qual & IEQUALIFIER_REPEAT))
  1259.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1260.                     {    if (verify())
  1261.                         cleanexit(EXIT_SUCCESS);
  1262.                     } else a = GAMEOVER;
  1263.             break;
  1264.             case SPACEBAR:
  1265.             case RETURN:
  1266.             case ENTER:
  1267.                 if (!(qual & IEQUALIFIER_REPEAT))
  1268.                     a = GAMEOVER;
  1269.             break;
  1270.             case NUMERICOPEN:
  1271.                 effect(FXCLICK);
  1272.                 setpointer(NORMAL);
  1273.                 underline(-1);
  1274.                                 brush--;
  1275.                                 if (brush <= 0 || brush > LASTOBJECT) // note sign issues
  1276.                     brush = LASTOBJECT;
  1277.                 stamp = brush;
  1278.                 break;
  1279.             case NUMERICCLOSE:
  1280.                 effect(FXCLICK);
  1281.                 setpointer(NORMAL);
  1282.                 underline(-1);
  1283.                 if (++brush > LASTOBJECT)
  1284.                     brush = 0;
  1285.                 stamp = brush;
  1286.                 break;
  1287.             break;
  1288.             case C:
  1289.                 effect(FXCENTRE); /* interesting */
  1290.                 x = FIELDX / 2;
  1291.                 y = FIELDY / 2;
  1292.             break;
  1293.             case ALPHAONE:
  1294.                 effect(FXCLICK);
  1295.                 stamp = GOLD;
  1296.                 break;
  1297.             case ALPHATWO:
  1298.                 effect(FXCLICK);
  1299.                 stamp = SILVER;
  1300.                 break;
  1301.             case ALPHATHREE:
  1302.                 effect(FXCLICK);
  1303.                 stamp = EMPTY;
  1304.                 break;
  1305.             case ALPHAFOUR:
  1306.                 effect(FXCLICK);
  1307.                 stamp = WOOD;
  1308.                 break;
  1309.             case ALPHAFIVE:
  1310.                 effect(FXCLICK);
  1311.                 stamp = STONE;
  1312.                 break;
  1313.             case ALPHASIX:
  1314.                 effect(FXCLICK);
  1315.                 stamp = METAL;
  1316.                 break;
  1317.             case ALPHASEVEN:
  1318.                 effect(FXCLICK);
  1319.                 stamp = ONE;
  1320.                 break;
  1321.             case ALPHAEIGHT:
  1322.                 effect(FXCLICK);
  1323.                 stamp = TWO;
  1324.                 break;
  1325.             case ALPHANINE:
  1326.                 effect(FXCLICK);
  1327.                 stamp = START;
  1328.                 break;
  1329.             case F1:
  1330.                 if (!(qual & IEQUALIFIER_REPEAT))
  1331.                 {    effect(FXCLICK);
  1332.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1333.                         fillfield(GOLD);
  1334.                     else setbrush(GOLD);
  1335.                 }
  1336.                 break;
  1337.             case F2:
  1338.                 if (!(qual & IEQUALIFIER_REPEAT))
  1339.                 {    effect(FXCLICK);
  1340.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1341.                         fillfield(SILVER);
  1342.                     else setbrush(SILVER);
  1343.                 }
  1344.                 break;
  1345.             case F3:
  1346.                 if (!(qual & IEQUALIFIER_REPEAT))
  1347.                 {    effect(FXCLICK);
  1348.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1349.                         fillfield(EMPTY);
  1350.                     else setbrush(EMPTY);
  1351.                 }
  1352.                 break;
  1353.             case F4:
  1354.                 if (!(qual & IEQUALIFIER_REPEAT))
  1355.                 {    effect(FXCLICK);
  1356.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1357.                         fillfield(WOOD);
  1358.                     else setbrush(WOOD);
  1359.                 }
  1360.                 break;
  1361.             case F5:
  1362.                 if (!(qual & IEQUALIFIER_REPEAT))
  1363.                 {    effect(FXCLICK);
  1364.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1365.                         fillfield(STONE);
  1366.                     else setbrush(STONE);
  1367.                 }
  1368.                 break;
  1369.             case F6:
  1370.                 if (!(qual & IEQUALIFIER_REPEAT))
  1371.                 {    effect(FXCLICK);
  1372.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1373.                         fillfield(METAL);
  1374.                     else setbrush(METAL);
  1375.                 }
  1376.                 break;
  1377.             case F7:
  1378.                 if (!(qual & IEQUALIFIER_REPEAT))
  1379.                 {    effect(FXCLICK);
  1380.                     setbrush(ONE);
  1381.                 }
  1382.                 break;
  1383.             case F8:
  1384.                 if (!(qual & IEQUALIFIER_REPEAT))
  1385.                 {    effect(FXCLICK);
  1386.                     setbrush(TWO);
  1387.                 }
  1388.                 break;
  1389.             case F9:
  1390.                 if (!(qual & IEQUALIFIER_REPEAT))
  1391.                 {    effect(FXCLICK);
  1392.                     setbrush(START);
  1393.                 }
  1394.                 break;
  1395.             case NUMERICZERO:
  1396.                 if (!(qual & IEQUALIFIER_REPEAT))
  1397.                 {    effect(FXCLICK);
  1398.                     if (!sticky)
  1399.                     {    sticky = TRUE;
  1400.                         stamp = brush;
  1401.                     } else
  1402.                     {       sticky = FALSE;
  1403.                                                 dot(x, y);
  1404.                 }       }
  1405.             break;
  1406.             case NUMERICDOT:
  1407.                 if (!(qual & IEQUALIFIER_REPEAT))
  1408.                 {    effect(FXCLICK);
  1409.                     stamp = brush;
  1410.                 }
  1411.             break;
  1412.             case NUMERICFOUR:
  1413.             case LEFT:
  1414.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1415.                     x = 0;
  1416.                 else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1417.                     x = xwrap(x - ALTJUMP);
  1418.                 else
  1419.                     x = xwrap(x - 1);
  1420.                 if (sticky)
  1421.                     stamp = brush;
  1422.                 break;
  1423.             case NUMERICSIX:
  1424.             case RIGHT:
  1425.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1426.                     x = FIELDX;
  1427.                 else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1428.                     x = xwrap(x + ALTJUMP);
  1429.                 else
  1430.                     x = xwrap(x + 1);
  1431.                 if (sticky)
  1432.                     stamp = brush;
  1433.                 break;
  1434.             case NUMERICEIGHT:
  1435.             case UP:
  1436.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1437.                     y = 0;
  1438.                 else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1439.                     y = ywrap(y - ALTJUMP);
  1440.                 else
  1441.                     y = ywrap(y - 1);
  1442.                 if (sticky)
  1443.                     stamp = brush;
  1444.                 break;
  1445.             case NUMERICFIVE:
  1446.             case NUMERICTWO:
  1447.             case DOWN:
  1448.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1449.                     y = FIELDY;
  1450.                 else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1451.                     y = ywrap(y + ALTJUMP);
  1452.                 else
  1453.                     y = ywrap(y + 1);
  1454.                 if (sticky)
  1455.                     stamp = brush;
  1456.                 break;
  1457.             case NUMERICSEVEN:
  1458.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1459.                 {    x = 0;
  1460.                     y = 0;
  1461.                 } else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1462.                 {    x = xwrap(x - ALTJUMP);
  1463.                     y = ywrap(y - ALTJUMP);
  1464.                 } else
  1465.                 {    x = xwrap(x - 1);
  1466.                     y = ywrap(y - 1);
  1467.                 }
  1468.                 if (sticky)
  1469.                     stamp = brush;
  1470.                 break;
  1471.             case NUMERICNINE:
  1472.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1473.                 {    x = FIELDX;
  1474.                     y = 0;
  1475.                 } else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1476.                 {    x = xwrap(x + ALTJUMP);
  1477.                     y = ywrap(y - ALTJUMP);
  1478.                 } else
  1479.                 {    x = xwrap(x + 1);
  1480.                     y = ywrap(y - 1);
  1481.                 }
  1482.                 if (sticky)
  1483.                     stamp = brush;
  1484.                 break;
  1485.             case NUMERICONE:
  1486.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1487.                 {    x = 0;
  1488.                     y = FIELDY;
  1489.                 } else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1490.                 {    x = xwrap(x - ALTJUMP);
  1491.                     y = ywrap(y + ALTJUMP);
  1492.                 } else
  1493.                 {    x = xwrap(x - 1);
  1494.                     y = ywrap(y + 1);
  1495.                 }
  1496.                 if (sticky)
  1497.                     stamp = brush;
  1498.                 break;
  1499.             case NUMERICTHREE:
  1500.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1501.                 {    x = FIELDX;
  1502.                     y = FIELDY;
  1503.                 } else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1504.                 {    x = xwrap(x + ALTJUMP);
  1505.                     y = ywrap(y + ALTJUMP);
  1506.                 } else
  1507.                 {    x = xwrap(x + 1);
  1508.                     y = ywrap(y + 1);
  1509.                 }
  1510.                 if (sticky)
  1511.                     stamp = brush;
  1512.                 break;
  1513.             default:
  1514.                 break;
  1515.             }
  1516.             if (x != lastx || y != lasty)
  1517.             {    updatesquare(lastx, lasty);
  1518.                 if (stamp > LASTOBJECT)
  1519.                     dot(x, y);
  1520.             }
  1521.             break;
  1522.         case IDCMP_MOUSEBUTTONS:
  1523.             updatesquare(x, y);
  1524.             switch (code)
  1525.             {
  1526.             case SELECTUP:
  1527.                 leftdown = FALSE;
  1528.                 break;
  1529.             case SELECTDOWN:
  1530.                 effect(FXCLICK);
  1531.                 leftdown = TRUE;
  1532.                 break;
  1533.             case MENUUP:
  1534.                 rightdown = FALSE;
  1535.                 brush = oldbrush;
  1536.                 oldbrush = ANYTHING;
  1537.             break;
  1538.             default:
  1539.                 /* MENUDOWN */
  1540.             break;
  1541.             }
  1542.         break;
  1543.         case IDCMP_CLOSEWINDOW:
  1544.             cleanexit(EXIT_SUCCESS);
  1545.         break;
  1546.         case IDCMP_REFRESHWINDOW:
  1547.             GT_BeginRefresh(MainWindowPtr);
  1548.             GT_EndRefresh(MainWindowPtr, TRUE);
  1549.         break;
  1550.         default:
  1551.             /* IDCMP_MENUVERIFY, IDCMP_INTUITICKS, IDCMP_ACTIVEWINDOW */
  1552.         break;
  1553.         }   }
  1554.         if (joy)
  1555.     {    if (GetMsg(JoyPortPtr))
  1556.         {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  1557.                 stamp = brush;
  1558.             deltax = (SBYTE) GameEvent.ie_position.ie_xy.ie_x;
  1559.             deltay = (SBYTE) GameEvent.ie_position.ie_xy.ie_y;
  1560.             if (GameEvent.ie_Qualifier == IEQUALIFIER_LEFTBUTTON)
  1561.                 stamp = brush;
  1562.             sendreadrequest();
  1563.         }
  1564.         if (deltax || deltay)
  1565.         {    if (!timer)
  1566.             {    TimerRqPtr->tr_node.io_Command = TR_ADDREQUEST;
  1567.                 TimerRqPtr->tr_time.tv_secs    = 0;
  1568.                 TimerRqPtr->tr_time.tv_micro   = JOYDELAY;
  1569.                 SendIO((struct IORequest *) TimerRqPtr);
  1570.                 timer = TRUE;
  1571.             } elif (CheckIO((struct IORequest *) TimerRqPtr))
  1572.                         // CheckIO() returns NULL if complete, pointer if incomplete.
  1573.             {    lastx = x;
  1574.                 lasty = y;
  1575.                 x = xwrap(x + deltax);
  1576.                 y = ywrap(y + deltay);    
  1577.                 updatesquare(lastx, lasty);
  1578.                 dot(x, y);
  1579.                 timer = FALSE;
  1580.     }    }    }
  1581.     if (leftdown || rightdown)
  1582.     {    pointerx = xpixeltosquare(MainWindowPtr->MouseX);
  1583.         pointery = ypixeltosquare(MainWindowPtr->MouseY);
  1584.         if (valid(pointerx, pointery))
  1585.         {    x = pointerx;
  1586.             y = pointery;
  1587.             stamp = brush;
  1588.             updatesquare(lastx, lasty);
  1589.         }
  1590.         else if (leftdown && pointerx == GADGETX &&
  1591.         (pointery == GOLDGADGET
  1592.         || pointery == SILVERGADGET
  1593.         || pointery == EMPTYGADGET
  1594.         || pointery == WOODGADGET
  1595.         || pointery == STONEGADGET
  1596.         || pointery == METALGADGET
  1597.         || pointery == ONEGADGET
  1598.         || pointery == TWOGADGET
  1599.         || pointery == STARTGADGET))
  1600.         {    switch (pointery)
  1601.             {
  1602.             case GOLDGADGET:
  1603.                 setbrush(GOLD);
  1604.                 break;
  1605.             case SILVERGADGET:
  1606.                 setbrush(SILVER);
  1607.                 break;
  1608.             case EMPTYGADGET:
  1609.                 setbrush(EMPTY);
  1610.                 break;
  1611.             case WOODGADGET:
  1612.                 setbrush(WOOD);
  1613.                 break;
  1614.             case STONEGADGET:
  1615.                 setbrush(STONE);
  1616.                 break;
  1617.             case METALGADGET:
  1618.                 setbrush(METAL);
  1619.                 break;
  1620.             case ONEGADGET:
  1621.                 setbrush(ONE);
  1622.                 break;
  1623.             case TWOGADGET:
  1624.                 setbrush(TWO);
  1625.                 break;
  1626.             case STARTGADGET:
  1627.                 setbrush(START);
  1628.                 break;
  1629.             default:
  1630.                 break;
  1631.     }    }    }
  1632.  
  1633.     if (stamp != NOSQUARE)
  1634.     {    if (stamp == START && board[level][x][y] != TELEPORT)
  1635.         {    if (x != startx[level] || y != starty[level])
  1636.             {    draw(startx[level], starty[level], EMPTY);
  1637.                 board[level][startx[level]][starty[level]] = EMPTY;
  1638.                 draw(x, y, START);
  1639.                 startx[level] = x;
  1640.                 starty[level] = y;
  1641.                 modified = TRUE;
  1642.                 clearthem = TRUE;
  1643.         }    }
  1644.         else if (x != startx[level] || y != starty[level])
  1645.         {    if (stamp == ONE || stamp == TWO)
  1646.             {    if (teleport[level][partner(stamp - ONE)].alive == FALSE || x != teleport[level][partner(stamp - ONE)].x || y != teleport[level][partner(stamp - ONE)].y)
  1647.                 {    if (teleport[level][stamp - ONE].alive == TRUE)
  1648.                     {    draw(teleport[level][stamp - ONE].x, teleport[level][stamp - ONE].y, EMPTY);
  1649.                         board[level][teleport[level][stamp - ONE].x][teleport[level][stamp - ONE].y] = EMPTY;
  1650.                     } else
  1651.                         teleport[level][stamp - ONE].alive = TRUE;
  1652.                     board[level][x][y] = TELEPORT;
  1653.                     draw(x, y, stamp);
  1654.                     teleport[level][stamp - ONE].x = x;
  1655.                     teleport[level][stamp - ONE].y = y;
  1656.                     modified = TRUE;
  1657.                     clearthem = TRUE;
  1658.             }    }
  1659.             else
  1660.             {    if (board[level][x][y] == TELEPORT)
  1661.                     if (teleport[level][0].alive == TRUE && x == teleport[level][0].x && y == teleport[level][0].y)
  1662.                         teleport[level][0].alive = FALSE;
  1663.                     else teleport[level][1].alive = FALSE;
  1664.                 draw(x, y, stamp);
  1665.                 board[level][x][y] = stamp;
  1666.                                 if (sticky)
  1667.                                         dot(x, y);
  1668.                 modified = TRUE;
  1669.                 clearthem = TRUE;
  1670. }    }    }    }
  1671.  
  1672. /* exit to title screen */
  1673.  
  1674. OffMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, NOITEM, NOSUB));
  1675. if (timer)
  1676. {    AbortIO((struct IORequest *) TimerRqPtr);
  1677.     WaitIO((struct IORequest *) TimerRqPtr);
  1678. }
  1679. if (oldbrush != ANYTHING)
  1680.     brush = oldbrush;
  1681. setpointer(NORMAL);
  1682. if (clearthem)
  1683.     clearhiscores();
  1684. matchteleports();
  1685. }
  1686.  
  1687. MODULE void help(UBYTE type)
  1688. {       TEXT  title[10];
  1689.         SWORD x, y;
  1690.         UBYTE i;
  1691.  
  1692.         effect(FXHELP);
  1693.         if (type == ORB)
  1694.         {   strcpy(title, "Creatures");
  1695.             x = 112;
  1696.             y = 118;
  1697.         } else
  1698.         {   strcpy(title, "Objects");
  1699.             x = 640;
  1700.             y = 28 + ((LASTOBJECT / 2) * 10);
  1701.         }
  1702.     if (!(HelpWindowPtr = (struct Window *) OpenWindowTags(NULL,
  1703.         WA_Left,          (SCREENXPIXEL / 2) - (x / 2),
  1704.         WA_Top,           (SCREENYPIXEL / 2) - (y / 2),
  1705.         WA_Width,         x,
  1706.         WA_Height,        y,
  1707.         WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS,
  1708.         WA_Title,         title,
  1709.         WA_Gadgets,       NULL,
  1710.         WA_CustomScreen,  ScreenPtr,
  1711.         WA_DragBar,       TRUE,
  1712.         WA_CloseGadget,   TRUE,
  1713.         WA_NoCareRefresh, TRUE,
  1714.         WA_Activate,      TRUE,
  1715.     TAG_DONE)))
  1716.     {    say("Can't open help window!", RED);
  1717.         anykey(TRUE);
  1718.     } else
  1719.         {   SetAPen(HelpWindowPtr->RPort, WHITE);
  1720.             if (type == ORB)
  1721.             {   for (i = 0; i <= CREATUREHELPS; i++)
  1722.                 {   Image.ImageData = ImageData[creaturehelp[i].image];
  1723.                     DrawImage
  1724.             (   HelpWindowPtr->RPort,
  1725.                 &Image,
  1726.                 10,
  1727.                 15 + (i * 10)
  1728.                 );
  1729.                     Move(HelpWindowPtr->RPort, 26, 20 + (i * 10));
  1730.                     Text(HelpWindowPtr->RPort, creaturehelp[i].desc, strlen(creaturehelp[i].desc));
  1731.             }   }
  1732.             else /* assumes (type == AFFIXER) */
  1733.             {   for (i = 0; i <= LASTOBJECT; i++)
  1734.                 {   Image.ImageData = ImageData[i];
  1735.                     if (i <= LASTOBJECT / 2)
  1736.                     {   Move(HelpWindowPtr->RPort, 26, 20 + (i * 10));
  1737.                         DrawImage
  1738.                         (   HelpWindowPtr->RPort,
  1739.                             &Image,
  1740.                             10,
  1741.                             15 + (i * 10)
  1742.                         );
  1743.                     } else
  1744.                     {   Move(HelpWindowPtr->RPort, 354, 10 + ((i - (LASTOBJECT / 2)) * 10));
  1745.                         DrawImage
  1746.                         (   HelpWindowPtr->RPort,
  1747.                             &Image,
  1748.                             338,
  1749.                             5 + ((i - (LASTOBJECT / 2)) * 10)
  1750.                         );
  1751.                     }
  1752.                     Text(HelpWindowPtr->RPort, objectdesc[i], strlen(objectdesc[i]));
  1753.             }   }
  1754.             helploop(type);
  1755. }       }
  1756.  
  1757. MODULE void helpmanual(void)
  1758. {
  1759. /*  struct NewAmigaGuide NAG = {NULL};
  1760.     AMIGAGUIDECONTEXT Handle;
  1761.  
  1762.     if (!(AmigaGuideBase = (struct AmigaGuideBase *) OpenLibrary("amigaguide.library", 0L)))
  1763.     {   say("Can't open amigaguide.library!", RED);
  1764.         anykey(TRUE);
  1765.         return;
  1766.     }
  1767.  
  1768.     // Fill in the NewAmigaGuide structure
  1769.     NAG.nag_Name = "PROGDIR:WormWars.guide";
  1770.     NAG.nag_Node = NULL;
  1771.     /* If you wanted a specific node of the AmigaGuide, you could set
  1772.     nag_Node to, for example, "Edit". */
  1773.     NAG.nag_Screen = ScreenPtr; // or NULL for default public screen
  1774.  
  1775.     // Open the AmigaGuide client
  1776.     if (Handle = OpenAmigaGuide(&NAG, TAG_DONE))
  1777.     {   /* if you opened it on the default public screen, add this line:
  1778.         ScreenToFront(ScreenPtr); */
  1779.         // Close the AmigaGuide client
  1780.         CloseAmigaGuide(Handle);
  1781.     } else
  1782.     {   /* if you want to know the reason, add this line:
  1783.         LONG rc = IoErr(); */
  1784.         DisplayBeep(ScreenPtr);
  1785.     }
  1786.     CloseLibrary((struct Library *) AmigaGuideBase); */
  1787.  
  1788.     if (SystemTagList("SYS:Utilities/MultiView >NIL: WormWars.guide", TAG_DONE) == -1)
  1789.         DisplayBeep(ScreenPtr);
  1790.     else ScreenToFront(ScreenPtr);
  1791. }
  1792.  
  1793. MODULE void helpabout(void)
  1794. {       SBYTE line;
  1795.         SLONG projectval;
  1796.         TEXT  projectstring[6], ks[5] = "    ", wb[5] = "    ";
  1797.         ULONG ksval = SysBase->LibNode.lib_Version,
  1798.               wbval = IconBase->lib_Version;
  1799.  
  1800.         effect(FXHELP);
  1801.     if (!(HelpWindowPtr = (struct Window *) OpenWindowTags(NULL,
  1802.     WA_Left,            (SCREENXPIXEL / 2) - (ABOUTXPIXEL / 2),
  1803.     WA_Top,                (SCREENYPIXEL / 2) - (ABOUTYPIXEL / 2),
  1804.     WA_Width,            ABOUTXPIXEL,
  1805.     WA_Height,            ABOUTYPIXEL,
  1806.     WA_IDCMP,            IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
  1807.     WA_Title,            "About Worm Wars",
  1808.     WA_Gadgets,            NULL,
  1809.     WA_CustomScreen,    ScreenPtr,
  1810.     WA_DragBar,            TRUE,
  1811.     WA_CloseGadget,        TRUE,
  1812.     WA_NoCareRefresh,    TRUE,
  1813.     WA_Activate,        TRUE,
  1814.     TAG_DONE)))
  1815.     {    say("Can't open About... window!", RED);
  1816.         anykey(TRUE);
  1817.     } else
  1818.     {    /* calculate project size */
  1819.         
  1820.         projectval =
  1821.             11                                                         /* header */
  1822.         +    ((HISCORES + 1) * (9 + NAMELENGTH + DATELENGTH + TIMELENGTH))
  1823.                                                                      /* high scores */
  1824.         +    ((levels + 1) * (7 + ((FIELDX + 1) * (FIELDY + 1))))     /* level data */
  1825.         +    levels
  1826.         +    strlen(VERSION)
  1827.                 +       1;
  1828.  
  1829.                 switch(ksval)
  1830.                 {
  1831.                 case 37:
  1832.                         strcpy(ks, "2.04");
  1833.                 break;
  1834.                 case 38:
  1835.                         strcpy(ks, "2.1 ");
  1836.                 break;
  1837.                 case 39:
  1838.                         strcpy(ks, "3.0 ");
  1839.                 break;
  1840.                 case 40:
  1841.                         strcpy(ks, "3.1 ");
  1842.                 break;
  1843.                 default:
  1844.                         strcpy(ks, "4.0+");
  1845.                 break;
  1846.                 }
  1847.  
  1848.                 switch(wbval)
  1849.                 {
  1850.                 case 37:
  1851.                         strcpy(wb, "2.04");
  1852.                 break;
  1853.                 case 38:
  1854.                         strcpy(wb, "2.1 ");
  1855.                 break;
  1856.                 case 39:
  1857.                         strcpy(wb, "3.0 ");
  1858.                 break;
  1859.                 case 40:
  1860.                 case 41:
  1861.                 case 42:
  1862.                 case 43:
  1863.                         strcpy(wb, "3.1 ");
  1864.                 break;
  1865.                 case 44:
  1866.                         strcpy(wb, "3.5 ");
  1867.                 break;
  1868.                 default:
  1869.                         strcpy(wb, "4.0+");
  1870.                 break;
  1871.                 }
  1872.                 
  1873.         SetAPen(HelpWindowPtr->RPort, worm[rand() % 4].colour);
  1874.         RectFill(HelpWindowPtr->RPort, 8, 13, ABOUTXPIXEL - 11, ABOUTYPIXEL - 6);
  1875.         SetAPen(HelpWindowPtr->RPort, ABOUTSHADOW);
  1876.         Move(HelpWindowPtr->RPort, 7, ABOUTYPIXEL - 5);
  1877.         Draw(HelpWindowPtr->RPort, 7, 12);
  1878.         Draw(HelpWindowPtr->RPort, ABOUTXPIXEL - 10, 12);
  1879.         SetAPen(HelpWindowPtr->RPort, ABOUTSHINE);
  1880.         Draw(HelpWindowPtr->RPort, ABOUTXPIXEL - 10, ABOUTYPIXEL - 5);
  1881.         Draw(HelpWindowPtr->RPort, 8, ABOUTYPIXEL - 5);
  1882.         SetAPen(HelpWindowPtr->RPort, BLACK);
  1883.         SetDrMd(HelpWindowPtr->RPort, JAM1);
  1884.         for (line = 0; line <= ABOUTLINES; line++)
  1885.         {    Move(HelpWindowPtr->RPort, about[line].x, about[line].y);
  1886.             Text(HelpWindowPtr->RPort, about[line].text, (SBYTE) strlen(about[line].text));
  1887.         }
  1888.         stcl_d(projectstring, projectval);
  1889.         align(projectstring, 5, ' ');
  1890.         Move(HelpWindowPtr->RPort, PROJECTX, PROJECTY);
  1891.         Text(HelpWindowPtr->RPort, projectstring, 5);
  1892.                 Move(HelpWindowPtr->RPort, KICKSTARTX, KICKSTARTY);
  1893.                 Text(HelpWindowPtr->RPort, ks, 4);
  1894.                 Move(HelpWindowPtr->RPort, WORKBENCHX, WORKBENCHY);
  1895.                 Text(HelpWindowPtr->RPort, wb, 4);
  1896.  
  1897.         DrawBevelBox(HelpWindowPtr->RPort, 18, 21, 47, 22, GT_VisualInfo, VisualInfoPtr);
  1898.         DrawImage(HelpWindowPtr->RPort, &About, 19, 22);
  1899.  
  1900.                 helploop(NOSQUARE);
  1901. }        }
  1902.  
  1903. MODULE void helploop(UBYTE type)
  1904. {   ABOOL                done = FALSE;
  1905.     UBYTE                objx, objy;
  1906.     UWORD                code, qual;
  1907.     SWORD                mousex, mousey;
  1908.     ULONG                class;
  1909.     struct IntuiMessage* MsgPtr;
  1910.  
  1911.     while(!done)
  1912.     {   Wait(1L << HelpWindowPtr->UserPort->mp_SigBit);
  1913.         while (MsgPtr = (struct IntuiMessage *) GetMsg(HelpWindowPtr->UserPort))
  1914.         {   class  = MsgPtr->Class;
  1915.             code   = MsgPtr->Code;
  1916.             qual   = MsgPtr->Qualifier;
  1917.             mousex = MsgPtr->MouseX;
  1918.             mousey = MsgPtr->MouseY;
  1919.             ReplyMsg((struct Message *) MsgPtr);
  1920.             switch(class)
  1921.             {
  1922.             case IDCMP_CLOSEWINDOW:
  1923.                 done = TRUE;
  1924.             break;
  1925.             case IDCMP_RAWKEY:
  1926.                 if (code == SPACEBAR || code == RETURN || code == ENTER || code == HELP)
  1927.                     done = TRUE;
  1928.                 elif (code == ESCAPE)
  1929.                 {   if (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  1930.                     {   if (verify())
  1931.                         {   CloseWindow(HelpWindowPtr);
  1932.                             cleanexit(EXIT_SUCCESS);
  1933.                    }   }
  1934.                    else done = TRUE;
  1935.                 }
  1936.             break;
  1937.             case IDCMP_MOUSEBUTTONS:
  1938.                 if (a == FIELDEDIT && type == AFFIXER)
  1939.                 {   objx = (mousex - 10) / 328; // which column
  1940.                     objy = (mousey - 13) / 10;  // which row
  1941.                     if ((objx == 0 || objx == 1) && (objy >= 0 && objy <= LASTOBJECT / 2))
  1942.                     {   if (objx)
  1943.                             setbrush(objy + 1 + (LASTOBJECT / 2));
  1944.                         else setbrush(objy);
  1945.                         done = TRUE;
  1946.                 }   }
  1947.             break;
  1948.             default:
  1949.             break;
  1950.     }   }   }
  1951.     CloseWindow(HelpWindowPtr);
  1952.     clearkybd();
  1953. }
  1954.  
  1955. void fileopen(ABOOL revert)
  1956. {   TEXT temp1[81] = {"Opened "}, temp2[3], newpathname[255];
  1957.  
  1958.     strcpy(newpathname, pathname);
  1959.     if (revert || (AslRequestTags(ASLRqPtr, ASL_Hail, "Open Fieldset", ASL_FuncFlags, FILF_PATGAD, TAG_DONE) && *(ASLRqPtr->rf_File)))
  1960.     {   if (!revert)
  1961.         {   strcpy(newpathname, ASLRqPtr->rf_Dir);
  1962.             AddPart(newpathname, ASLRqPtr->rf_File, 254);
  1963.         }
  1964.         if (!loadfields(newpathname))
  1965.         {   strcpy(pathname, newpathname);
  1966.             strcat(temp1, pathname);
  1967.             strcat(temp1, " (");
  1968.             stci_d(temp2, levels);
  1969.             strcat(temp1, temp2);
  1970.             strcat(temp1, " levels).");
  1971.             say(temp1, WHITE);
  1972.             if (a == FIELDEDIT)
  1973.                 turborender();
  1974.             else hiscores();
  1975.         } else
  1976.         {   strcpy(temp1, "Couldn't open ");
  1977.             strcat(temp1, newpathname);
  1978.             strcat(temp1, "!");
  1979.             say(temp1, WHITE);
  1980.     }   }
  1981.     if (a == GAMEOVER)
  1982.         anykey(TRUE);
  1983. }
  1984.  
  1985. void filesaveas(ABOOL flag)
  1986. {    ABOOL    cont = TRUE;
  1987.     TEXT    newpathname[255], temp1[SAYLIMIT + 1], temp2[3];
  1988.         struct DiskObject* InfoHandle;
  1989.  
  1990.     /* flag is TRUE for 'save as...', FALSE for 'save'. */
  1991.  
  1992.     strcpy(newpathname, pathname);
  1993.     if (flag)
  1994.         if (AslRequestTags(ASLRqPtr, ASL_Hail, "Save Fieldset", ASL_FuncFlags, FILF_PATGAD | FILF_SAVE, TAG_DONE) && *(ASLRqPtr->rf_File) != 0)
  1995.         {   strcpy(newpathname, ASLRqPtr->rf_Dir);
  1996.             AddPart(newpathname, ASLRqPtr->rf_File, 254);
  1997.         } else cont = FALSE;
  1998.     if (cont)
  1999.     {    strcpy(temp1, "Saving ");
  2000.     strcat(temp1, newpathname);
  2001.     strcat(temp1, "...");
  2002.     say(temp1, WHITE);
  2003.     if (savefields(newpathname))
  2004.         {   strcpy(pathname, newpathname);
  2005.             if (icons)
  2006.             {   InfoHandle = GetDiskObjectNew(DEFAULTSET);
  2007.                 InfoHandle->do_CurrentX = NO_ICON_POSITION;
  2008.                 InfoHandle->do_CurrentY = NO_ICON_POSITION;
  2009.                 if (!PutDiskObject(pathname, InfoHandle))
  2010.                 {   say("Couldn't write .info file!", RED);
  2011.                     anykey(TRUE);
  2012.             }   }
  2013.             strcpy(temp1, "Saved ");
  2014.             strcat(temp1, pathname);
  2015.             strcat(temp1, " (");
  2016.             stci_d(temp2, levels);
  2017.             strcat(temp1, temp2);
  2018.             strcat(temp1, " levels).");
  2019.         } else
  2020.         {   strcpy(temp1, "Couldn't save ");
  2021.             strcat(temp1, newpathname);
  2022.             strcat(temp1, "!");
  2023.         }
  2024.         say(temp1, WHITE);
  2025.         if (a == GAMEOVER)
  2026.             anykey(TRUE);
  2027. }   }
  2028.  
  2029. MODULE void freefx(void)
  2030. {   SBYTE i;
  2031.  
  2032.     stopfx();
  2033.     if (!AudioClosed)
  2034.     {   CloseDevice((struct IORequest *) AudioRqPtr[0]);
  2035.         AudioClosed = TRUE;
  2036.     }
  2037.     for (i = 0; i <= 3; i++)
  2038.     {   if (AudioRqPtr[i])
  2039.         {   DeleteIORequest(AudioRqPtr[i]);
  2040.             AudioRqPtr[i] = NULL;
  2041.         }
  2042.         if (AudioPortPtr[i])
  2043.         {   // if we ReplyMsg() first, that causes crashes
  2044.             DeleteMsgPort(AudioPortPtr[i]);
  2045.             AudioPortPtr[i] = NULL;
  2046.     }   }
  2047.     if (fbase)
  2048.     {   FreeMem(fbase, fsize);
  2049.         fbase = NULL;
  2050.     }
  2051.     if (FilePtr)
  2052.     {   Close(FilePtr);
  2053.         FilePtr = NULL;
  2054. }   }
  2055.  
  2056. void gameinput(void)
  2057. {   ABOOL                done;
  2058.     UWORD                code, qual;
  2059.     ULONG                class;
  2060.     struct IntuiMessage* MsgPtr;
  2061.     SBYTE                keyplayer;
  2062.     UBYTE                which;
  2063.  
  2064.     for (which = 0; which <= NUMKEYS; which++)
  2065.         key[which].down = FALSE;
  2066.  
  2067. /* keyboard */
  2068.  
  2069. while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  2070. {   class = MsgPtr->Class;
  2071.     code  = MsgPtr->Code;
  2072.     qual  = MsgPtr->Qualifier;
  2073.     ReplyMsg((struct Message *) MsgPtr);
  2074.     if (class == IDCMP_RAWKEY && (!(qual & IEQUALIFIER_REPEAT)) && code < KEYUP)
  2075.     {   switch(code)
  2076.         {
  2077.         case M:
  2078.             toggle(M);
  2079.         break;
  2080.     case F:
  2081.             toggle(F);
  2082.         break;
  2083.     case P:
  2084.             clearkybd();
  2085.             say("Paused...press P to unpause", WHITE);
  2086.             pausetimer();
  2087.             done = FALSE;
  2088.             while (!done)
  2089.             {    Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  2090.                 while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  2091.                 {    class = MsgPtr->Class;
  2092.                     code  = MsgPtr->Code;
  2093.                     qual  = MsgPtr->Qualifier;
  2094.                     ReplyMsg((struct Message *) MsgPtr);
  2095.                     if (class == IDCMP_RAWKEY && (!(qual & IEQUALIFIER_REPEAT)))
  2096.                     {    if (code == ESCAPE)
  2097.                         {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2098.                             {    if (verify())
  2099.                                     cleanexit(EXIT_SUCCESS);
  2100.                             } else
  2101.                             {    a = GAMEOVER;
  2102.                                 done = TRUE;
  2103.                                 worm[0].lives = worm[1].lives = worm[2].lives = worm[3].lives = 0;
  2104.                         }    }
  2105.                         else if (code == M)
  2106.                             toggle(M);
  2107.                         else if (code == F)
  2108.                             toggle(F);
  2109.                         else if (code == P)
  2110.                         {    say("Unpaused", WHITE);
  2111.                             done = TRUE;
  2112.             }    }    }    }
  2113.             unpausetimer();
  2114.         break;
  2115.     case ESCAPE:
  2116.         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2117.         {   if (verify())
  2118.                 cleanexit(EXIT_SUCCESS);
  2119.         } else
  2120.         {   a = GAMEOVER;
  2121.             worm[0].lives = worm[1].lives = worm[2].lives = worm[3].lives = 0;
  2122.         }
  2123.         break;
  2124.     default:
  2125.        for (which = 0; which <= NUMKEYS; which++)
  2126.            if (code == key[which].scancode)
  2127.                key[which].down = TRUE;
  2128.         break;
  2129.     }   }    
  2130.     elif (class == IDCMP_CLOSEWINDOW)
  2131.         cleanexit(EXIT_SUCCESS);
  2132.     elif (class == IDCMP_REFRESHWINDOW)
  2133.     {   GT_BeginRefresh(MainWindowPtr);
  2134.         GT_EndRefresh(MainWindowPtr, TRUE);
  2135. }   }
  2136. /* Received but ignored: IDCMP_ACTIVEWINDOW, IDCMP_MOUSEBUTTONS and
  2137. IDCMP_INTUITICKS. */
  2138.  
  2139. for (which = 0; which <= NUMKEYS; which++)
  2140. {    if (key[which].down)
  2141.     {    if (key[which].special == ONEHUMAN)
  2142.         {    if (worm[0].control == HUMAN && worm[1].control != HUMAN)
  2143.                 wormqueue(0, key[which].deltax, key[which].deltay);
  2144.             else if (worm[0].control != HUMAN && worm[1].control == HUMAN)
  2145.                 wormqueue(1, key[which].deltax, key[which].deltay);
  2146.         } else if (key[which].special == MOVE || key[which].special == AMMO)
  2147.         {   if (worm[key[which].player].control == HUMAN)
  2148.                 keyplayer = key[which].player;
  2149.             else if (key[which].player == 1 && worm[0].control == HUMAN && worm[1].control != HUMAN)
  2150.                 keyplayer = 0;
  2151.             else if (key[which].player == 0 && worm[1].control == HUMAN && worm[0].control != HUMAN)
  2152.                 keyplayer = 1;
  2153.             else keyplayer = -1;
  2154.             if (keyplayer != -1)
  2155.                 wormqueue(keyplayer, key[which].deltax, key[which].deltay);
  2156.         } else if (worm[1].lives) /* assumes key[which].special == TRAINER */
  2157.             train(key[which].scancode);
  2158. }    }
  2159.  
  2160. /* joystick */
  2161.  
  2162. if (worm[2].control == HUMAN)
  2163.     while (GetMsg(JoyPortPtr))
  2164.     {    if (GameEvent.ie_position.ie_xy.ie_x != 0 || GameEvent.ie_position.ie_xy.ie_y != 0)
  2165.             wormqueue(2, GameEvent.ie_position.ie_xy.ie_x, GameEvent.ie_position.ie_xy.ie_y);
  2166.         if (GameEvent.ie_Code == IECODE_LBUTTON)
  2167.             wormqueue(2, 0, 0);
  2168.         sendreadrequest();
  2169. }    }
  2170.  
  2171. void hiscores(void)
  2172. {   SBYTE which;
  2173.     TEXT  tempstring[NAMELENGTH + 1];
  2174.  
  2175. /* render hiscores
  2176.  
  2177. #################################################### # = shadow
  2178. #   #   #   #                      #     #         % % = shine
  2179. #   #   #   #                      #     #         %
  2180. #   #   #   #                      #     #         %
  2181. #   #   #   #                      #     #         %
  2182. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
  2183.  
  2184. SetDrMd(MainWindowPtr->RPort, JAM1);
  2185. for (which = 0; which <= HISCORES; which++)
  2186. {    if (hiscore[which].player == -1)
  2187.         SetAPen(MainWindowPtr->RPort, LIGHTGREY);
  2188.     else SetAPen(MainWindowPtr->RPort, worm[hiscore[which].player].colour);
  2189.         RectFill(MainWindowPtr->RPort, 104, TSOFFSET + 1 + (which * HISCOREDISTANCE), 536, TSOFFSET + 10 + (which * HISCOREDISTANCE));
  2190.     if (hiscore[which].player == 0)
  2191.         SetAPen(MainWindowPtr->RPort, DARKGREEN);
  2192.     else if (hiscore[which].player == 1)
  2193.         SetAPen(MainWindowPtr->RPort, DARKRED);
  2194.     else if (hiscore[which].player == 2)
  2195.         SetAPen(MainWindowPtr->RPort, DARKBLUE);
  2196.     else if (hiscore[which].player == 3)
  2197.         SetAPen(MainWindowPtr->RPort, DARKYELLOW);
  2198.     else SetAPen(MainWindowPtr->RPort, DARKGREY);
  2199.         Move(MainWindowPtr->RPort, 103, TSOFFSET + 11 + (which * HISCOREDISTANCE));
  2200.         Draw(MainWindowPtr->RPort, 103, TSOFFSET +      (which * HISCOREDISTANCE));
  2201.         Draw(MainWindowPtr->RPort, 537, TSOFFSET +      (which * HISCOREDISTANCE));
  2202.  
  2203.     if (hiscore[which].player != -1)
  2204.     {    /* divider bars */
  2205.     
  2206.                 Move(MainWindowPtr->RPort, 182 - 55, TSOFFSET +      (which * HISCOREDISTANCE));
  2207.                 Draw(MainWindowPtr->RPort, 182 - 55, TSOFFSET + 10 + (which * HISCOREDISTANCE));
  2208.                 Move(MainWindowPtr->RPort, 254 - 55, TSOFFSET +      (which * HISCOREDISTANCE));
  2209.                 Draw(MainWindowPtr->RPort, 254 - 55, TSOFFSET + 10 + (which * HISCOREDISTANCE));
  2210.                 Move(MainWindowPtr->RPort, 290 - 55, TSOFFSET +      (which * HISCOREDISTANCE));
  2211.                 Draw(MainWindowPtr->RPort, 290 - 55, TSOFFSET + 10 + (which * HISCOREDISTANCE));
  2212.                 Move(MainWindowPtr->RPort, 416,      TSOFFSET +      (which * HISCOREDISTANCE));
  2213.                 Draw(MainWindowPtr->RPort, 416,      TSOFFSET + 10 + (which * HISCOREDISTANCE));
  2214.                 Move(MainWindowPtr->RPort, 464,      TSOFFSET +      (which * HISCOREDISTANCE));
  2215.                 Draw(MainWindowPtr->RPort, 464,      TSOFFSET + 10 + (which * HISCOREDISTANCE));
  2216.     }
  2217.     
  2218.     SetAPen(MainWindowPtr->RPort, WHITE);
  2219.         Move(MainWindowPtr->RPort, 159 - 55, TSOFFSET + 11 + (which * HISCOREDISTANCE));
  2220.         Draw(MainWindowPtr->RPort, 482 + 55, TSOFFSET + 11 + (which * HISCOREDISTANCE));
  2221.         Draw(MainWindowPtr->RPort, 482 + 55, TSOFFSET +  1 + (which * HISCOREDISTANCE));
  2222.     SetAPen(MainWindowPtr->RPort, BLACK);
  2223.  
  2224.     if (hiscore[which].player != -1)
  2225.     {    stci_d(tempstring, which + 1);
  2226.         tempstring[1] = '.';
  2227.                 Move(MainWindowPtr->RPort, 161 - 55, TSOFFSET + 8 + (which * HISCOREDISTANCE));
  2228.         Text(MainWindowPtr->RPort, tempstring, 2);
  2229.         stci_d(tempstring, hiscore[which].score);
  2230.         align(tempstring, 7, ' ');
  2231.                 Move(MainWindowPtr->RPort, 193 - 55, TSOFFSET + 8 + (which * HISCOREDISTANCE));
  2232.         Text(MainWindowPtr->RPort, tempstring, 7);
  2233.         if (hiscore[which].level == -1)
  2234.             strcpy(tempstring, "All");
  2235.         else
  2236.         {    stci_d(tempstring, hiscore[which].level);
  2237.             align(tempstring, 3, ' ');
  2238.         }
  2239.                 Move(MainWindowPtr->RPort, 206, TSOFFSET + 8 + (which * HISCOREDISTANCE));
  2240.         Text(MainWindowPtr->RPort, tempstring, 3);
  2241.                 Move(MainWindowPtr->RPort, 241, TSOFFSET + 8 + (which * HISCOREDISTANCE));
  2242.         Text(MainWindowPtr->RPort, hiscore[which].name, strlen(hiscore[which].name));
  2243.                 Move(MainWindowPtr->RPort, 418, TSOFFSET + 8 + (which * HISCOREDISTANCE));
  2244.         Text(MainWindowPtr->RPort, hiscore[which].time, strlen(hiscore[which].time));
  2245.                 Move(MainWindowPtr->RPort, 466, TSOFFSET + 8 + (which * HISCOREDISTANCE));
  2246.         Text(MainWindowPtr->RPort, hiscore[which].date, strlen(hiscore[which].date));
  2247. }    }
  2248. SetDrMd(MainWindowPtr->RPort, JAM2);
  2249. }
  2250.  
  2251. void hiscorenames(void)
  2252. {
  2253. ULONG                    class;
  2254. ABOOL                    done;
  2255. SBYTE                    which;
  2256. struct IntuiMessage*    MsgPtr;
  2257.  
  2258. for (which = 0; which <= HISCORES; which++)
  2259.     if (hiscore[which].fresh)
  2260.     {    GT_SetGadgetAttrs(StringGadgetPtr[which], MainWindowPtr, NULL, GA_Disabled, FALSE, GTST_String, worm[hiscore[which].player].name, TAG_DONE);
  2261.         ActivateGadget(StringGadgetPtr[which], MainWindowPtr, NULL);
  2262.         done = FALSE;
  2263.         while (!done)
  2264.         {    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  2265.             {    class = MsgPtr->Class;
  2266.                 GT_ReplyIMsg(MsgPtr);
  2267.                 if (class == IDCMP_GADGETUP)
  2268.                     done = TRUE;
  2269.                 else if (class == IDCMP_MOUSEBUTTONS)
  2270.                     ActivateGadget(StringGadgetPtr[which], MainWindowPtr, NULL);
  2271.                 else if (class == IDCMP_REFRESHWINDOW)
  2272.                 {    GT_BeginRefresh(MainWindowPtr);
  2273.                     GT_EndRefresh(MainWindowPtr, TRUE);
  2274.         }    }    }
  2275.         GT_SetGadgetAttrs(StringGadgetPtr[which], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2276.                 effect(FXAPPLAUSE);
  2277.         strcpy(hiscore[which].name, ((struct StringInfo *) (StringGadgetPtr[which]->SpecialInfo))->Buffer);
  2278.         if (hiscore[which].name[0] >= 97 && hiscore[which].name[0] <= 123)
  2279.             hiscore[which].name[0] -= 32;
  2280.         strcpy(worm[hiscore[which].player].name, hiscore[which].name);
  2281.         hiscore[which].fresh = FALSE;
  2282.         hiscores();
  2283. }    }
  2284.  
  2285. MODULE ABOOL beginfx(void)
  2286. {           SBYTE    i;
  2287.     PERSIST    UBYTE    chan[]    = {15};
  2288.  
  2289.     for (i = 0; i <= 3; i++)
  2290.     {   eversent[i] = FALSE;
  2291.         if (!(AudioPortPtr[i] = (struct MsgPort *) CreateMsgPort()))
  2292.         {   freefx();
  2293.             draw(MUSICICON, ICONY, BLACKENED);
  2294.             mode = FALSE;
  2295.             say("No port for effects!", RED);
  2296.             anykey(TRUE);
  2297.             return FALSE;
  2298.         } else if (!(AudioRqPtr[i] = (struct IOAudio *) CreateIORequest(AudioPortPtr[i], sizeof(struct IOAudio))))
  2299.         {   freefx();
  2300.             draw(MUSICICON, ICONY, BLACKENED);
  2301.             mode = FALSE;
  2302.             say("No I/O memory for effects!", RED);
  2303.             anykey(TRUE);
  2304.             return FALSE;
  2305.     }   }
  2306.     AudioRqPtr[0]->ioa_Request.io_Message.mn_ReplyPort      = AudioPortPtr[0];
  2307.     AudioRqPtr[0]->ioa_Request.io_Message.mn_Node.ln_Pri    = 127;
  2308.     AudioRqPtr[0]->ioa_AllocKey                             = 0;
  2309.     AudioRqPtr[0]->ioa_Data                                 = chan;
  2310.     AudioRqPtr[0]->ioa_Length                               = 1;
  2311.     if (AudioClosed = OpenDevice(AUDIONAME, 0L, (struct IORequest *) AudioRqPtr[0], 0L))
  2312.     {   freefx();
  2313.         draw(MUSICICON, ICONY, BLACKENED);
  2314.         mode = FALSE;
  2315.         say("Can't allocate all channels for effects!", RED);
  2316.         anykey(TRUE);
  2317.         return FALSE;
  2318.     } else
  2319.     {   for (i = 1; i <= 3; i++)
  2320.             CopyMem(AudioRqPtr[0], AudioRqPtr[i], sizeof(struct IOAudio));
  2321.         return TRUE;
  2322. }   }
  2323.  
  2324. void resettime(void)
  2325. {   GetSysTime(StartValPtr);
  2326.     srand((UWORD) StartValPtr->tv_micro);
  2327. }
  2328.  
  2329. void rundown(SBYTE player)
  2330. {       ABOOL                done = FALSE, flag = FALSE;
  2331.     TEXT                 tempstring[6];
  2332.     SBYTE                i, j, x, y;
  2333.         UBYTE                multiply = worm[player].multi * players;
  2334.     UWORD                counter = 0, code, qual;
  2335.     ULONG                levelbonus, timebonus, tailbonus, class;
  2336.     struct IntuiMessage* MsgPtr;
  2337.  
  2338.     clearscreen();
  2339.     SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2340.  
  2341.     Image.ImageData = ImageData[TREASURE];
  2342.     DrawImage(MainWindowPtr->RPort, &Image, 201, 103);
  2343.     Move(MainWindowPtr->RPort, 218, 108);
  2344.     Text(MainWindowPtr->RPort, "Level Bonus:    ## x ##00 =", 27);
  2345.         stci_d(tempstring, multiply);
  2346.     align(tempstring, 2, ' ');
  2347.     Move(MainWindowPtr->RPort, 218 + (FONTX * 21), 108);
  2348.     Text(MainWindowPtr->RPort, tempstring, 2);
  2349.     stci_d(tempstring, level - 1);
  2350.     align(tempstring, 2, ' ');
  2351.     Move(MainWindowPtr->RPort, 218 + (FONTX * 16), 108);
  2352.     Text(MainWindowPtr->RPort, tempstring, 2);
  2353.  
  2354.     Image.ImageData = ImageData[CLOCK];
  2355.     DrawImage(MainWindowPtr->RPort, &Image, 201, 111);
  2356.     Move(MainWindowPtr->RPort, 218, 116);
  2357.     Text(MainWindowPtr->RPort, " Time Bonus: ##:## x  ##0 =", 27);
  2358.         stci_d(tempstring, multiply);
  2359.     align(tempstring, 2, ' ');
  2360.     Move(MainWindowPtr->RPort, 226 + (FONTX     * 21), 116);
  2361.     Text(MainWindowPtr->RPort, tempstring, 2);
  2362.     stci_d(tempstring, secondsleft / 60);
  2363.     align(tempstring, 2, ' ');
  2364.     Move(MainWindowPtr->RPort, 226 + (FONTX * 12), 116);
  2365.     Text(MainWindowPtr->RPort, tempstring, 2);
  2366.     stci_d(tempstring, secondsleft % 60);
  2367.     align(tempstring, 2, '0');
  2368.     Move(MainWindowPtr->RPort, 226 + (FONTX * 15), 116);
  2369.     Text(MainWindowPtr->RPort, tempstring, 2);
  2370.  
  2371.     Image.ImageData = ImageData[FIRSTTAIL + player];
  2372.     DrawImage(MainWindowPtr->RPort, &Image, 201, 119);
  2373.     Move(MainWindowPtr->RPort, 218, 124);
  2374.     Text(MainWindowPtr->RPort, " Tail Bonus:  #### x   ## =", 27);
  2375.         stci_d(tempstring, multiply);
  2376.     align(tempstring, 2, ' ');
  2377.         Move(MainWindowPtr->RPort, 226 + (FONTX * 22), 124);
  2378.         Text(MainWindowPtr->RPort, tempstring, 2);
  2379.     for (x = 0; x <= FIELDX; x++)
  2380.         for (y = 0; y <= FIELDY; y++)
  2381.             if (field[x][y] == FIRSTTAIL + player)
  2382.                 counter++;
  2383.     stci_d(tempstring, counter);
  2384.     align(tempstring, 4, ' ');
  2385.     Move(MainWindowPtr->RPort, 226 + (FONTX * 13), 124);
  2386.     Text(MainWindowPtr->RPort, tempstring, 4);
  2387.  
  2388.     levelbonus = (level - 1) * 100 * multiply;
  2389.     timebonus = secondsleft * 10 * multiply;
  2390.     tailbonus = counter * multiply;
  2391.  
  2392.     for (i = 0; i <= 3; i++)
  2393.         if (worm[i].control != NONE)
  2394.             for (j = 0; j <= LASTOBJECT; j++)
  2395.                 stat(i, j);
  2396.  
  2397.     while (!done)
  2398.     {   while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  2399.         {   class  = MsgPtr->Class;
  2400.         code   = MsgPtr->Code;
  2401.         qual   = MsgPtr->Qualifier;
  2402.         ReplyMsg((struct Message *) MsgPtr);
  2403.             if (class == IDCMP_RAWKEY && (!(qual & IEQUALIFIER_REPEAT)) && code < KEYUP)
  2404.                 done = TRUE;
  2405.         }
  2406.         if (done)
  2407.     {   wormscore
  2408.             (   player,
  2409.                 (levelbonus / multiply) +
  2410.                 ( timebonus / multiply) +
  2411.                 ( tailbonus / multiply)
  2412.             );
  2413.             levelbonus = timebonus = tailbonus = 0;
  2414.         }
  2415.         SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2416.         stci_d(tempstring, levelbonus);
  2417.         align(tempstring, 5, ' ');
  2418.         Move(MainWindowPtr->RPort, 218 + (FONTX * 27), 108);
  2419.         Text(MainWindowPtr->RPort, tempstring, 5);
  2420.  
  2421.         stci_d(tempstring, timebonus);
  2422.         align(tempstring, 5, ' ');
  2423.         Move(MainWindowPtr->RPort, 226 + (FONTX * 26), 116);
  2424.         Text(MainWindowPtr->RPort, tempstring, 5);
  2425.  
  2426.         stci_d(tempstring, tailbonus);
  2427.         align(tempstring, 5, ' ');
  2428.         Move(MainWindowPtr->RPort, 226 + (FONTX * 26), 124);
  2429.         Text(MainWindowPtr->RPort, tempstring, 5);
  2430.  
  2431.         done = TRUE;
  2432.         if (levelbonus)
  2433.         {   levelbonus -= multiply;
  2434.             wormscore(player, 1);
  2435.             done = FALSE;
  2436.         }
  2437.         if (timebonus)
  2438.         {   timebonus -= multiply;
  2439.             wormscore(player, 1);
  2440.             done = FALSE;
  2441.         }
  2442.         if (tailbonus)
  2443.         {   tailbonus -= multiply;
  2444.             wormscore(player, 1);
  2445.             done = FALSE;
  2446.         }
  2447.         effect(FXCLICK);
  2448.     }
  2449.     clearkybd();
  2450.     effect(FXRIFF);
  2451.     for (i = 0; i <= 3; i++)
  2452.         if (worm[i].control == HUMAN)
  2453.         {   flag = TRUE;
  2454.             break;
  2455.         }
  2456.     waitasec();
  2457.     if (flag)
  2458.         anykey(FALSE);
  2459. }
  2460.  
  2461. void say(STRPTR sentence, COLOUR colour)
  2462. {   SBYTE length = (SBYTE) strlen(sentence);
  2463.  
  2464.     /* truncate text */
  2465.  
  2466.     if (length > SAYLIMIT)
  2467.         *(sentence + SAYLIMIT - 1) = *(sentence + SAYLIMIT - 2) = *(sentence + SAYLIMIT - 3) = '.';
  2468.  
  2469.     /* clear areas to left, right and top of text, respectively */
  2470.  
  2471.     SetAPen(MainWindowPtr->RPort, BLACK);
  2472.     RectFill
  2473.     (   MainWindowPtr->RPort,
  2474.         SAYSTARTXPIXEL,
  2475.         2,
  2476.         (SCREENXPIXEL / 2) - (length * FONTX / 2),
  2477.         10
  2478.     );
  2479.     RectFill
  2480.     (   MainWindowPtr->RPort,
  2481.         (SCREENXPIXEL / 2) + (length * FONTX / 2) + 1,
  2482.         2,
  2483.         SAYENDXPIXEL,
  2484.         10
  2485.     );
  2486.     Move(MainWindowPtr->RPort, (SCREENXPIXEL / 2) - (length * FONTX / 2), 2);
  2487.     Draw(MainWindowPtr->RPort, (SCREENXPIXEL / 2) + (length * FONTX / 2), 2);
  2488.  
  2489.     /* render shadow text */
  2490.     
  2491.     SetAPen(MainWindowPtr->RPort, MEDIUMGREY);
  2492.     Move(MainWindowPtr->RPort, (SCREENXPIXEL / 2) - (length * FONTX / 2) + 1, FONTY + 1);
  2493.     Text(MainWindowPtr->RPort, sentence, length);
  2494.     
  2495.     /* render actual text */
  2496.     
  2497.     SetDrMd(MainWindowPtr->RPort, JAM1);
  2498.     SetAPen(MainWindowPtr->RPort, colour);
  2499.     Move(MainWindowPtr->RPort, (SCREENXPIXEL / 2) - (length * FONTX / 2), FONTY);
  2500.     Text(MainWindowPtr->RPort, sentence, length);
  2501.     SetDrMd(MainWindowPtr->RPort, JAM2);
  2502. }
  2503.     
  2504. void sendreadrequest(void)
  2505. {    JoyRqPtr->io_Command = GPD_READEVENT;
  2506.     JoyRqPtr->io_Flags   = NULL;
  2507.     JoyRqPtr->io_Length  = sizeof(struct InputEvent);
  2508.     JoyRqPtr->io_Data    = (APTR) &GameEvent;
  2509.     SendIO((struct IORequest *) JoyRqPtr);
  2510. }
  2511.  
  2512. MODULE void setpointer(SBYTE pointer) {
  2513. switch (pointer) {
  2514. case GOLD:
  2515.         SetRGB4(&ScreenPtr->ViewPort, 17, 10, 10,  2);          /* fill */
  2516.     SetRGB4(&ScreenPtr->ViewPort, 18,  8,  4,  2);        /* shadow */
  2517.     SetRGB4(&ScreenPtr->ViewPort, 19, 12, 12,  2);        /* shine */
  2518.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2519.     break;
  2520. case SILVER:
  2521.         SetRGB4(&ScreenPtr->ViewPort, 17, 11, 11, 11);          /* fill */
  2522.     SetRGB4(&ScreenPtr->ViewPort, 18,  6,  6,  6);        /* shadow */
  2523.     SetRGB4(&ScreenPtr->ViewPort, 19, 15, 15, 15);        /* shine */
  2524.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2525.     break;
  2526. case EMPTY:
  2527.         SetRGB4(&ScreenPtr->ViewPort, 17,  5,  5,  5);          /* fill */
  2528.     SetRGB4(&ScreenPtr->ViewPort, 18,  0,  0,  0);        /* shadow */
  2529.         SetRGB4(&ScreenPtr->ViewPort, 19,  8,  8,  8);          /* shine */
  2530.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2531.     break;
  2532. case WOOD:
  2533.     SetRGB4(&ScreenPtr->ViewPort, 17,  8,  4,  2);        /* fill */
  2534.         SetRGB4(&ScreenPtr->ViewPort, 18,  5,  5,  5);          /* shadow */
  2535.         SetRGB4(&ScreenPtr->ViewPort, 19, 10, 10,  2);          /* shine */
  2536.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2537.     break;
  2538. case STONE:
  2539.     SetRGB4(&ScreenPtr->ViewPort, 17,  0,  0,  0);        /* fill */
  2540.         SetRGB4(&ScreenPtr->ViewPort, 18,  5,  5,  5);          /* shadow */
  2541.         SetRGB4(&ScreenPtr->ViewPort, 19,  8,  8,  8);          /* shine */
  2542.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2543.     break;
  2544. case METAL:
  2545.     SetRGB4(&ScreenPtr->ViewPort, 17,  6,  6, 15);        /* fill */
  2546.     SetRGB4(&ScreenPtr->ViewPort, 18,  3,  3, 15);        /* shadow */
  2547.         SetRGB4(&ScreenPtr->ViewPort, 19, 11, 11, 11);          /* shine */
  2548.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2549.     break;
  2550. default:
  2551.     SetRGB4(&ScreenPtr->ViewPort, 17, 14,  4,  4);        /* fill */
  2552.     SetRGB4(&ScreenPtr->ViewPort, 18,  3,  3,  3);        /* shadow */
  2553.     SetRGB4(&ScreenPtr->ViewPort, 19, 12, 12, 12);        /* shine */
  2554.     ClearPointer(MainWindowPtr);
  2555.     break; }
  2556. }
  2557.  
  2558. void stat(SBYTE player, SBYTE line)
  2559. {   ABOOL print = TRUE;
  2560.     SBYTE i, len, theline;
  2561.     TEXT  output[9];
  2562.  
  2563.     strcpy(output, "        "); /* 8 spaces */
  2564.     switch (line)
  2565.     {
  2566.     case BONUS:
  2567.         do
  2568.         {   worm[player].oldscore += (LIFEMODULO - (worm[player].oldscore % LIFEMODULO));
  2569.             if (worm[player].score >= worm[player].oldscore)
  2570.             {   worm[player].lives++;
  2571.                 stat(player, LIFE);
  2572.         }   }
  2573.         while (worm[player].score > worm[player].oldscore);
  2574.         worm[player].oldscore = worm[player].score;
  2575.         if (worm[player].multi > 1)
  2576.             SetAPen(MainWindowPtr->RPort, WHITE);
  2577.         else SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2578.         stcl_d(output, worm[player].score);
  2579.         for (i = 0; i <= 8; i++)
  2580.             if (!output[i])
  2581.                 output[i] = ' ';
  2582.         theline = 0;
  2583.         if (worm[player].score <= 999999)
  2584.             len = 6;
  2585.         else
  2586.         {   // assert(worm[player].score <= 99999999);
  2587.             len = 8;
  2588.         }
  2589.     break;
  2590.     case LIFE:
  2591.         if (worm[player].lives > STARTLIVES)
  2592.         {   SetAPen(MainWindowPtr->RPort, WHITE);
  2593.             if (worm[player].lives > LIVESLIMIT)
  2594.                 worm[player].lives = LIVESLIMIT;
  2595.         } else SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2596.         stci_d(output, worm[player].lives);
  2597.         for (i = 0; i <= 2; i++)
  2598.             if (!output[i])
  2599.                 output[i] = ' ';
  2600.         theline = 1;
  2601.         len = 3;
  2602.     break;
  2603.     case BIAS:
  2604.         if (worm[player].bias > 0)
  2605.         {   if (worm[player].bias > BIASLIMIT)
  2606.                 worm[player].bias = BIASLIMIT;
  2607.             SetAPen(MainWindowPtr->RPort, WHITE);
  2608.         } else SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2609.         stci_d(output, worm[player].bias);
  2610.         for (i = 0; i <= 2; i++)
  2611.             if (!output[i])
  2612.                 output[i] = ' ';
  2613.         theline = 2;
  2614.         len = 3;
  2615.     break;
  2616.     case NITRO:
  2617.             if (worm[player].nitro)
  2618.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2619.             else SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2620.             if (worm[player].speed == FAST)
  2621.                 strcpy(output, "Fast  ");
  2622.             elif (worm[player].speed == NORMAL)
  2623.                 strcpy(output, "Normal");
  2624.             elif (worm[player].speed == SLOW)
  2625.                 strcpy(output, "Slow  ");
  2626.             else
  2627.             {   // assert(worm[player].speed == VERYSLOW);
  2628.                 strcpy(output, "V.Slow");
  2629.             }
  2630.             theline = 3;
  2631.             len = 6;
  2632.         break;
  2633.     case AMMO:
  2634.             if (worm[player].ammo)
  2635.             {   if (worm[player].ammo > AMMOLIMIT)
  2636.                     worm[player].ammo = AMMOLIMIT;
  2637.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2638.             } else SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2639.             stci_d(output, worm[player].ammo);
  2640.             for (i = 0; i <= 2; i++)
  2641.                 if (!output[i])
  2642.                     output[i] = ' ';
  2643.             if (iso)
  2644.                 theline = 4;
  2645.             else theline = 5;
  2646.             len = 3;
  2647.         break;
  2648.     case POWER:
  2649.             switch(worm[player].power)
  2650.             {
  2651.             case 0:
  2652.                 SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2653.                 strcpy(output, "Single");
  2654.             break;
  2655.             case 2:
  2656.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2657.                 strcpy(output, "Triple");
  2658.             break;
  2659.             case 4:
  2660.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2661.                 strcpy(output, "Quint.");
  2662.             break;
  2663.             case 6:
  2664.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2665.                 strcpy(output, "Sept. ");
  2666.             break;
  2667.             default:
  2668.             break;
  2669.             }
  2670.             if (iso)
  2671.                 theline = 5;
  2672.             else theline = 6;
  2673.             len = 6;
  2674.         break;
  2675.     case ARMOUR:
  2676.             if (worm[player].armour > MODELIMIT)
  2677.                 worm[player].armour = MODELIMIT;
  2678.             if (worm[player].mode == ARMOUR)
  2679.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2680.             else SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2681.             stci_d(output, worm[player].armour);
  2682.             for (i = 0; i <= 2; i++)
  2683.                 if (!output[i])
  2684.                     output[i] = ' ';
  2685.             if (iso)
  2686.                 theline = 6;
  2687.             else theline = 8;
  2688.             len = 3;
  2689.     break;
  2690.     case TONGUE:
  2691.         if (worm[player].tongue > MODELIMIT)
  2692.             worm[player].tongue = MODELIMIT;
  2693.         if (worm[player].mode == TONGUE)
  2694.             SetAPen(MainWindowPtr->RPort, WHITE);
  2695.         else SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2696.         stci_d(output, worm[player].tongue);
  2697.         for (i = 0; i <= 2; i++)
  2698.             if (!output[i])
  2699.                 output[i] = ' ';
  2700.         if (iso)
  2701.             theline = 7;
  2702.         else theline = 9;
  2703.         len = 3;
  2704.     break;
  2705.     default:
  2706.         print = FALSE;
  2707.     break;
  2708.     }
  2709.  
  2710.     /* Sometimes stat() is called with a valid line, yet an invalid player.
  2711.     Defensive programming currently ensures that this is not a problem, but
  2712.     it would be better to fix the bug. */
  2713.  
  2714.     if (print)
  2715.     {   if (iso)
  2716.         {   switch(player)
  2717.             {
  2718.             case 0:
  2719.                 Move(MainWindowPtr->RPort, 0  ,   8 + (theline * FONTY));
  2720.             break;
  2721.             case 1:
  2722.                 Move(MainWindowPtr->RPort, 528, 189 + (theline * FONTY));
  2723.             break;
  2724.             case 2:
  2725.                 Move(MainWindowPtr->RPort, 66 ,   8 + (theline * FONTY));
  2726.             break;
  2727.             case 3:
  2728.                 Move(MainWindowPtr->RPort, 592, 189 + (theline * FONTY));
  2729.             break;
  2730.             default:
  2731.                 // assert(0);
  2732.             break;
  2733.         }   }
  2734.         else
  2735.         {   Move
  2736.             (   MainWindowPtr->RPort,
  2737.                 (FONTX * 3) + (worm[player].statx * ENDXPIXEL),
  2738.                 STARTYPIXEL + 6 + (theline * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  2739.             );
  2740.         }
  2741.         Text(MainWindowPtr->RPort, output, len);
  2742. }   }
  2743.  
  2744. void stopfx(void)
  2745. {   SBYTE i;
  2746.  
  2747.     if (mode == FX)
  2748.         for (i = 0; i <= 3; i++)
  2749.             // CheckIO() returns NULL if complete, pointer if incomplete? (!)
  2750.             if (eversent[i] && (!(CheckIO((struct IORequest *) AudioRqPtr[i]))))
  2751.             {   AbortIO((struct IORequest *) AudioRqPtr[i]);
  2752.                 WaitIO((struct IORequest *) AudioRqPtr[i]);
  2753. }           }
  2754.  
  2755. void titlescreen(void)
  2756. {   SBYTE                lisa = 0, object = LASTOBJECT, player;
  2757.     SWORD                descx = FIRSTDESCX;
  2758.     ULONG                class;
  2759.     UWORD                code, qual;
  2760.     struct IntuiMessage* MsgPtr;
  2761.     struct Gadget*       WhichGadgetPtr;
  2762.     struct MenuItem*     ItemPtr;
  2763.  
  2764.     effect(FXLAUNCH);
  2765.     Forbid();
  2766.     MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  2767.     Permit();
  2768.     clearscreen();
  2769.  
  2770.     SetMenuStrip(MainWindowPtr, MenuPtr);
  2771.     for (player = 0; player <= 3; player++)
  2772.         GT_SetGadgetAttrs(CycleGadgetPtr[player], MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2773.     GT_SetGadgetAttrs(RandomGadgetPtr, MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2774.     GT_SetGadgetAttrs(CheckboxGadgetPtr, MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2775.  
  2776.     clearkybd();
  2777.     clearjoystick();
  2778.     hiscores();
  2779.     hiscorenames();
  2780.  
  2781.         SetDrMd(MainWindowPtr->RPort, JAM1);
  2782.         SetAPen(MainWindowPtr->RPort, BLACK);
  2783.         Move(MainWindowPtr->RPort, STARTXPIXEL + 9, TSOFFSET +  86);
  2784.         Text(MainWindowPtr->RPort, "Spacebar: Field Editor ", 23);
  2785.         Move(MainWindowPtr->RPort, STARTXPIXEL + 9, TSOFFSET +  98);
  2786.         Text(MainWindowPtr->RPort, "       F: Sound Effects", 23);
  2787.         Move(MainWindowPtr->RPort, STARTXPIXEL + 9, TSOFFSET + 110);
  2788.         Text(MainWindowPtr->RPort, "       M: Music        ", 23);
  2789.         SetAPen(MainWindowPtr->RPort, WHITE);
  2790.         Move(MainWindowPtr->RPort, STARTXPIXEL + 8, TSOFFSET +  85);
  2791.         Text(MainWindowPtr->RPort, "Spacebar: Field Editor ", 23);
  2792.         Move(MainWindowPtr->RPort, STARTXPIXEL + 8, TSOFFSET +  97);
  2793.         Text(MainWindowPtr->RPort, "       F: Sound Effects", 23);
  2794.         Move(MainWindowPtr->RPort, STARTXPIXEL + 8, TSOFFSET + 109);
  2795.         Text(MainWindowPtr->RPort, "       M: Music        ", 23);
  2796.         SetDrMd(MainWindowPtr->RPort, JAM2);
  2797.  
  2798.     DrawImage(MainWindowPtr->RPort, &Logo, 203, 22);
  2799.  
  2800.     do
  2801.     {    TimerRqPtr->tr_node.io_Command    = TR_ADDREQUEST;
  2802.                 TimerRqPtr->tr_time.tv_secs     = 0;
  2803.         TimerRqPtr->tr_time.tv_micro    = ANIMDELAY;
  2804.         SendIO((struct IORequest *) TimerRqPtr);
  2805.  
  2806.         if (descx == FIRSTDESCX)
  2807.         {    if (++object > LASTOBJECT)
  2808.                 object = 0;
  2809.             say(objectdesc[object], WHITE);
  2810.             Image.ImageData = ImageData[object];
  2811.             DrawImage(MainWindowPtr->RPort, &Image, SECONDDESCX, DESCY);
  2812.         }
  2813.         SetAPen(MainWindowPtr->RPort, BLACK);
  2814.         Move(MainWindowPtr->RPort, descx - 1, DESCY - 1);
  2815.         Draw(MainWindowPtr->RPort, descx - 1, DESCY + 1 + SQUAREY);
  2816.         Move(MainWindowPtr->RPort, descx + 1 + SQUAREX, DESCY - 1);
  2817.         Draw(MainWindowPtr->RPort, descx + 1 + SQUAREX, DESCY + 1 + SQUAREY);
  2818.         Image.ImageData = ImageData[object];
  2819.         DrawImage(MainWindowPtr->RPort, &Image, descx, DESCY);
  2820.         if (++descx > SECONDDESCX)
  2821.             descx = FIRSTDESCX;
  2822.  
  2823.         while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  2824.         {    WhichGadgetPtr = (struct Gadget *) MsgPtr->IAddress;
  2825.             class = MsgPtr->Class;
  2826.             code  = MsgPtr->Code;
  2827.             qual  = MsgPtr->Qualifier;
  2828.             GT_ReplyIMsg(MsgPtr);
  2829.                         switch (class) {
  2830.             case IDCMP_RAWKEY:
  2831.                             if (!(qual & IEQUALIFIER_REPEAT))
  2832.                             switch (code) {
  2833.                     case F:
  2834.                         toggle(F);
  2835.                         break;
  2836.                     case M:
  2837.                         toggle(M);
  2838.                         break;
  2839.                     case SPACEBAR:
  2840.                         effect(FXCLICK);
  2841.                         a = FIELDEDIT;
  2842.                         break;
  2843.                     case F1:
  2844.                     case ALPHAONE:
  2845.                     case NUMERICONE:
  2846.                         effect(FXCLICK);
  2847.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2848.                         {    if (--worm[0].control < 0)
  2849.                                 worm[0].control = 2;
  2850.                         } else
  2851.                         {    if (++worm[0].control > 2)
  2852.                                 worm[0].control = 0;
  2853.                         }
  2854.                         GT_SetGadgetAttrs(CycleGadgetPtr[0], MainWindowPtr, NULL, GTCY_Active, worm[0].control, TAG_DONE);
  2855.                         break;
  2856.                     case F2:
  2857.                     case ALPHATWO:
  2858.                     case NUMERICTWO:
  2859.                         effect(FXCLICK);
  2860.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2861.                         {    if (--worm[1].control < 0)
  2862.                                 worm[1].control = 2;
  2863.                         } else
  2864.                         {    if (++worm[1].control > 2)
  2865.                                 worm[1].control = 0;
  2866.                         }
  2867.                         GT_SetGadgetAttrs(CycleGadgetPtr[1], MainWindowPtr, NULL, GTCY_Active, worm[1].control, TAG_DONE);
  2868.                     break;
  2869.                     case F3:
  2870.                     case ALPHATHREE:
  2871.                     case NUMERICTHREE:
  2872.                         effect(FXCLICK);
  2873.                         if (joy)
  2874.                         {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2875.                             {    if (--worm[2].control < 0)
  2876.                                     worm[2].control = 2;
  2877.                             } else
  2878.                             {    if (++worm[2].control > 2)
  2879.                                     worm[2].control = 0;
  2880.                         }    }
  2881.                         else if (worm[2].control == NONE)
  2882.                             worm[2].control = AMIGA;
  2883.                         else
  2884.                             worm[2].control = NONE;
  2885.                         GT_SetGadgetAttrs(CycleGadgetPtr[2], MainWindowPtr, NULL, GTCY_Active, worm[2].control, TAG_DONE);
  2886.                     break;
  2887.                     case F4:
  2888.                     case ALPHAFOUR:
  2889.                     case NUMERICFOUR:
  2890.                         effect(FXCLICK);
  2891.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2892.                         {    if (--worm[3].control < 0)
  2893.                                 worm[3].control = 2;
  2894.                         } else
  2895.                         {    if (++worm[3].control > 2)
  2896.                                 worm[3].control = 0;
  2897.                         }
  2898.                         GT_SetGadgetAttrs(CycleGadgetPtr[3], MainWindowPtr, NULL, GTCY_Active, worm[3].control, TAG_DONE);
  2899.                     break;
  2900.                     case RETURN:
  2901.                     case ENTER:
  2902.                         a = PLAYGAME;
  2903.                         break;
  2904.                     case I:
  2905.                         effect(FXCLICK);
  2906.                         iso = !iso;
  2907.                         GT_SetGadgetAttrs(CheckboxGadgetPtr, MainWindowPtr, NULL, GTCB_Checked, iso, TAG_DONE);
  2908.                         break;
  2909.                                         case S:
  2910.                                             effect(FXCLICK);
  2911.                                             randomflag = !randomflag;
  2912.                                             GT_SetGadgetAttrs(RandomGadgetPtr, MainWindowPtr, NULL, GTCB_Checked, randomflag, TAG_DONE);
  2913.                     break;
  2914.                     case ESCAPE:
  2915.                         if (verify())
  2916.                             cleanexit(EXIT_SUCCESS);
  2917.                         break;
  2918.                     case HELP:
  2919.                         helpabout();
  2920.                         break;
  2921.                     case INTERNATIONALONE:
  2922.                         if (lisa == 2)
  2923.                         {    say(FIRSTLISA, RED);
  2924.                             anykey(FALSE);
  2925.                             lisa = 0;
  2926.                         } else
  2927.                             lisa = 1;
  2928.                         break;
  2929.                     case INTERNATIONALTWO:
  2930.                         if (lisa == 1)
  2931.                         {    say(SECONDLISA, BLUE);
  2932.                             anykey(FALSE);
  2933.                             lisa = 0;
  2934.                         } else
  2935.                             lisa = 2;
  2936.                         break;
  2937.                     default:
  2938.                         break;
  2939.                     }
  2940.                 break;
  2941.             case IDCMP_MENUPICK:
  2942.                 while (code != MENUNULL)
  2943.                 {    ItemPtr = ItemAddress(MenuPtr, code);
  2944.                     switch (MENUNUM(code))
  2945.                     {
  2946.                     case MN_PROJECT:
  2947.                         switch (ITEMNUM(code))
  2948.                         {
  2949.                         case IN_NEW:
  2950.                             effect(FXFILENEW);
  2951.                             newfields();
  2952.                             say("New done.", WHITE);
  2953.                             anykey(TRUE);
  2954.                             say(objectdesc[object], WHITE);
  2955.                         break;
  2956.                         case IN_OPEN:
  2957.                             effect(FXFILEOPEN);
  2958.                             fileopen(FALSE);
  2959.                             say(objectdesc[object], WHITE);
  2960.                         break;
  2961.                         case IN_REVERT:
  2962.                             fileopen(TRUE);
  2963.                             say(objectdesc[object], WHITE);
  2964.                         break;
  2965.                         case IN_SAVE:
  2966.                             effect(FXFILESAVE);
  2967.                             filesaveas(FALSE);
  2968.                             say(objectdesc[object], WHITE);
  2969.                             break;
  2970.                         case IN_SAVEAS:
  2971.                             effect(FXFILESAVEAS);
  2972.                             filesaveas(TRUE);
  2973.                             say(objectdesc[object], WHITE);
  2974.                             break;
  2975.                         case IN_QUIT:
  2976.                             if (verify())
  2977.                                 cleanexit(EXIT_SUCCESS);
  2978.                             break;
  2979.                         default:
  2980.                             break;
  2981.                         }
  2982.                         break;
  2983.                     case MN_SETTINGS:
  2984.                         switch(ITEMNUM(code))
  2985.                         {
  2986.                         case IN_CREATEICONS:
  2987.                             if (ItemPtr->Flags & CHECKED)
  2988.                                 icons = TRUE;
  2989.                             else icons = FALSE;
  2990.                         break;
  2991.                         default:
  2992.                         break;
  2993.                         }
  2994.                     break;
  2995.                     case MN_HELP:
  2996.                         switch(ITEMNUM(code))
  2997.                         {
  2998.                         case IN_MANUAL:
  2999.                             helpmanual();
  3000.                         break;
  3001.                         case IN_ABOUT:
  3002.                 helpabout();
  3003.             break;
  3004.                         case IN_CREATURES:
  3005.                             help(ORB);
  3006.                         break;
  3007.                         case IN_OBJECTS:
  3008.                             help(AFFIXER);
  3009.                         break;
  3010.                         }
  3011.             break;
  3012.                     default:
  3013.             break;
  3014.             }
  3015.             code = ItemPtr->NextSelect;
  3016.         }
  3017.         break;
  3018.             case IDCMP_MOUSEBUTTONS:
  3019.                 if (code == SELECTDOWN)
  3020.                     if (ignore)
  3021.                         ignore = FALSE;
  3022.                     else a = PLAYGAME;
  3023.                 break;
  3024.             case IDCMP_REFRESHWINDOW:
  3025.                 GT_BeginRefresh(MainWindowPtr);
  3026.                 GT_EndRefresh(MainWindowPtr, TRUE);
  3027.                 break;
  3028.             case IDCMP_GADGETUP:
  3029.                 if (WhichGadgetPtr == CheckboxGadgetPtr)
  3030.                     iso = !iso;
  3031.                                 elif (WhichGadgetPtr == RandomGadgetPtr)
  3032.                                     randomflag = !randomflag;
  3033.                 else
  3034.                 {    for (player = 0; player <= 3; player++)
  3035.                         if (WhichGadgetPtr == CycleGadgetPtr[player])
  3036.                         {    if (code == HUMAN && player == 2 && (!joy))
  3037.                             {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  3038.                                     worm[2].control = NONE;
  3039.                                 else
  3040.                                     worm[2].control = AMIGA;
  3041.                                 GT_SetGadgetAttrs(CycleGadgetPtr[2], MainWindowPtr, NULL, GTCY_Active, worm[2].control, TAG_DONE);
  3042.                             } else
  3043.                                 worm[player].control = code;
  3044.                             break;
  3045.                         }
  3046.                 }
  3047.                 break;
  3048.             case IDCMP_ACTIVEWINDOW:
  3049.                 ignore = TRUE;
  3050.                 break;
  3051.             case IDCMP_CLOSEWINDOW:
  3052.                 cleanexit(EXIT_SUCCESS);
  3053.                 break;
  3054.             default:
  3055.                 /* IDCMP_MENUVERIFY, IDCMP_INTUITICKS */
  3056.                 break;
  3057.         }    }
  3058.         if (joy && GetMsg(JoyPortPtr))
  3059.         {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  3060.                 a = PLAYGAME;
  3061.             sendreadrequest();
  3062.         }
  3063.         if (a == PLAYGAME)
  3064.         {    if (worm[0].control == NONE && worm[1].control == NONE && worm[2].control == NONE && worm[3].control == NONE)
  3065.             {    say("No worms active!", WHITE);
  3066.                 anykey(TRUE);
  3067.                 a = GAMEOVER;
  3068.         }    }
  3069.                 // CheckIO() returns NULL if complete, pointer if incomplete.
  3070.                 if (CheckIO((struct IORequest *) TimerRqPtr))
  3071.             draw(CLOCKICON, ICONY, CLOCK);
  3072.         else draw(CLOCKICON, ICONY, BLACKENED);
  3073.         WaitIO((struct IORequest *) TimerRqPtr);
  3074.     } while (a == GAMEOVER);
  3075.  
  3076.     for (player = 0; player <= 3; player++)
  3077.         GT_SetGadgetAttrs(CycleGadgetPtr[player], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  3078.     GT_SetGadgetAttrs(CheckboxGadgetPtr, MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  3079.     GT_SetGadgetAttrs(RandomGadgetPtr, MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  3080.     Image.ImageData = ImageData[BLACKENED];
  3081.     DrawImage(MainWindowPtr->RPort, &Image, FIRSTDESCX, DESCY);
  3082.     DrawImage(MainWindowPtr->RPort, &Image, SECONDDESCX, DESCY);
  3083.     if (a == FIELDEDIT)
  3084.         fieldedit();
  3085.     else
  3086.     {    newgame();
  3087.         clearkybd();
  3088.         Forbid();
  3089.         MainWindowPtr->Flags |= WFLG_RMBTRAP;
  3090.         Permit();
  3091. }    }
  3092.  
  3093. MODULE void toggle(SBYTE key)
  3094. {   PERSIST ABOOL songstarted = FALSE;
  3095.  
  3096.     switch(key)
  3097.     {
  3098.     case F:
  3099.         if (mode == FX) /* F in FX mode: no sound */
  3100.         {   freefx();
  3101.             mode = FALSE;
  3102.             draw(MUSICICON, ICONY, BLACKENED);
  3103.         } else if (fxable != FAILED) /* F otherwise: change to FX mode */
  3104.         {   if (mode == MUSIC) /* stop any music that is playing */
  3105.             {   StopPlayer();
  3106.                 FreePlayer();
  3107.             }
  3108.             if (fxable == DEFER) /* load samples if needed */
  3109.                 loadthefx();
  3110.             if (fxable == SUCCEEDED) /* if we have samples in memory */
  3111.             {   if (beginfx())
  3112.                 {   mode = FX;
  3113.                     effect(FXLAUNCH);
  3114.                     draw(MUSICICON, ICONY, FX);
  3115.         }   }   }
  3116.     break;
  3117.     case M:
  3118.         if (mode == MUSIC) /* M in MUSIC mode: no sound */
  3119.         {   StopPlayer();
  3120.             FreePlayer();
  3121.             mode = FALSE;
  3122.             draw(MUSICICON, ICONY, BLACKENED);
  3123.         } else if (musicable != FAILED) /* M otherwise: change to music mode */
  3124.         {   if (mode == FX) /* stop any samples that are playing */
  3125.                 freefx();
  3126.             /* Of course, these statements are ordered in this
  3127.             way for a reason, so don't change it. :-) */
  3128.             if (musicable == DEFER)
  3129.                 loadthemusic();
  3130.             if (musicable == SUCCEEDED)
  3131.             {   if (GetPlayer(0))
  3132.                 {   say("No channels for music!", RED);
  3133.                     anykey(TRUE);
  3134.                     mode = FALSE;
  3135.                     draw(MUSICICON, ICONY, BLACKENED);
  3136.                 } else
  3137.                 {   if (songstarted)
  3138.                         ContModule(SongPtr);
  3139.                     else
  3140.                     {   PlayModule(SongPtr);
  3141.                         songstarted = TRUE;
  3142.                     }
  3143.                     mode = MUSIC;
  3144.                     draw(MUSICICON, ICONY, MUSIC);
  3145.         }   }   }
  3146.     break;
  3147.     default:
  3148.         flash(2);
  3149.         // assert(0);
  3150.     break;
  3151. }   }
  3152.     
  3153. MODULE void underline(SBYTE square)
  3154. {    /* Removes old underline, draws new underline.
  3155.     
  3156.     square: which square-type to underline, or -1 for clear only.
  3157.     Squares which do not correspond to any pseudo-gadgets
  3158.     (eg. objects) are converted to -1s. */
  3159.  
  3160.     PERSIST    SWORD oldy = -1;
  3161.             SWORD y;
  3162.  
  3163.     switch(square)
  3164.     {
  3165.     case GOLD:
  3166.         y = UNDERLINEOFFSET;
  3167.         break;
  3168.     case SILVER:
  3169.         y = UNDERLINEOFFSET + (SQUAREY *  3);
  3170.         break;
  3171.     case EMPTY:
  3172.         y = UNDERLINEOFFSET + (SQUAREY *  6);
  3173.         break;
  3174.     case WOOD:
  3175.         y = UNDERLINEOFFSET + (SQUAREY *  9);
  3176.         break;
  3177.     case STONE:
  3178.         y = UNDERLINEOFFSET + (SQUAREY * 12);
  3179.         break;
  3180.     case METAL:
  3181.         y = UNDERLINEOFFSET + (SQUAREY * 15);
  3182.         break;
  3183.     case ONE:
  3184.         y = UNDERLINEOFFSET + (SQUAREY * 18);
  3185.         break;
  3186.     case TWO:
  3187.         y = UNDERLINEOFFSET + (SQUAREY * 21);
  3188.         break;
  3189.     case START:
  3190.         y = UNDERLINEOFFSET + (SQUAREY * 24);
  3191.         break;
  3192.     default:
  3193.         square = -1;
  3194.         break;
  3195.     }
  3196.  
  3197.     if (oldy != -1)
  3198.     {    SetAPen(MainWindowPtr->RPort, BLACK);
  3199.         Move(MainWindowPtr->RPort, STARTXPIXEL - SQUAREX + 1, oldy);
  3200.         Draw(MainWindowPtr->RPort, STARTXPIXEL - SQUAREX + 1, oldy + SQUAREY + 3);
  3201.     }
  3202.     if (square != -1)
  3203.     {    SetAPen(MainWindowPtr->RPort, WHITE);
  3204.         Move(MainWindowPtr->RPort, STARTXPIXEL - SQUAREX + 1, y);
  3205.         Draw(MainWindowPtr->RPort, STARTXPIXEL - SQUAREX + 1, y + SQUAREY + 3);
  3206.         oldy = y;
  3207. }    }
  3208.  
  3209. ABOOL verify(void)
  3210. {    pausetimer();
  3211.     if (modified && (EasyRequest(MainWindowPtr, &EasyStruct, NULL) == 0))
  3212.         return FALSE;
  3213.     else return TRUE;
  3214.     unpausetimer();
  3215. }
  3216.  
  3217. void waitasec(void)
  3218. {   Delay(50);
  3219. }
  3220.  
  3221. void systemsetup(void)
  3222. {    worm[0].control    = NONE;
  3223.     worm[1].control    = HUMAN;
  3224.     worm[2].control    = NONE;
  3225.     worm[3].control = AMIGA;
  3226. }
  3227.  
  3228. ABOOL ZOpen(STRPTR fieldname, ABOOL write)
  3229. {    if (!write)
  3230.         if (FilePtr = Open(fieldname, MODE_OLDFILE))
  3231.             return TRUE;
  3232.         else return FALSE;
  3233.     else
  3234.         if (FilePtr = Open(fieldname, MODE_NEWFILE))
  3235.             return TRUE;
  3236.         else return FALSE;
  3237. }
  3238. ABOOL ZRead(STRPTR IOBuffer, ULONG length)
  3239. {    if (Read(FilePtr, IOBuffer, length) == length)
  3240.         return TRUE;
  3241.     else return FALSE;
  3242. }
  3243. ABOOL ZWrite(STRPTR IOBuffer, ULONG length)
  3244. {    if (Write(FilePtr, IOBuffer, length) == length)
  3245.         return TRUE;
  3246.     else return FALSE;
  3247. }
  3248. ABOOL ZClose(void)
  3249. {    if (Close(FilePtr))
  3250.     {    FilePtr = NULL;
  3251.         return TRUE;
  3252.     } else
  3253.     {    /* "If Close() returns DOSFALSE, the user has already cancelled an
  3254.         error requester and the function has already freed the FileHandle
  3255.         (and even marked it so any attempt to close it again will bring up
  3256.         the "Software Failure" requester). Therefore FilePtr should be set
  3257.         to zero in any case." - Jilles Tjoelker. */
  3258.  
  3259.         FilePtr = NULL;
  3260.         return FALSE;
  3261. }    }
  3262.  
  3263. void timing(void)
  3264. {    ;
  3265. }
  3266.  
  3267. MODULE void loadthefx(void)
  3268. {   UBYTE*        p8data;
  3269.     TEXT          saystring[SAYLIMIT + 1];
  3270.     SBYTE         code = 0, i,
  3271.                   iobuffer[8]; /* buffer for 8SVX.VHDR  */
  3272.     SBYTE*        psample[2];  /* sample pointers */
  3273.     struct Chunk* p8Chunk;     /* pointers for 8SVX parsing */
  3274.     Voice8Header* pVoice8Header;
  3275.     ULONG         rd8count;
  3276.  
  3277.     say("Loading sound effects...", WHITE);
  3278.     fxable = SUCCEEDED;
  3279.  
  3280.     for (i = 0; i <= SAMPLES; i++)
  3281.         samp[i].base = NULL;
  3282.  
  3283.     for (i = 0; i <= SAMPLES; i++)
  3284.     {   if (!(FilePtr = Open(samp[i].filename, MODE_OLDFILE)))
  3285.             code = 1;                               /* can't open file */
  3286.         else
  3287.         {   rd8count = Read(FilePtr, iobuffer, 8L);
  3288.             if (rd8count == -1)
  3289.                 code = 2;                           /* can't read file */
  3290.             elif (rd8count < 8)
  3291.                 code = 3;                           /* not an IFF 8SVX; too short */
  3292.             else
  3293.             {   p8Chunk = (struct Chunk *) iobuffer;
  3294.                 if (p8Chunk->ckID != ID_FORM)
  3295.                     code = 4;                       /* not an IFF FORM */
  3296.                 elif (!(fbase = (UBYTE *) AllocMem(fsize = p8Chunk->ckSize, MEMF_PUBLIC | MEMF_CLEAR)))
  3297.                     code = 5;                       /* no memory for read */
  3298.                 else
  3299.                 {   p8data = fbase;
  3300.                     rd8count = Read(FilePtr, p8data, p8Chunk->ckSize);
  3301.                     if (rd8count == -1)
  3302.                         code = 6;                   /* read error */
  3303.                     elif (rd8count < p8Chunk->ckSize)
  3304.                         code = 7;                   /* malformed IFF; too short */
  3305.                     elif (MAKE_ID(*p8data, *(p8data + 1), *(p8data + 2), *(p8data + 3)) != ID_8SVX)
  3306.                         code = 8;                   /* not an IFF 8SVX */
  3307.                     else
  3308.                     {   p8data = p8data + 4;
  3309.                         while (p8data < fbase + fsize)
  3310.                         {   p8Chunk = (struct Chunk *) p8data;
  3311.                             switch(p8Chunk->ckID)
  3312.                             {
  3313.                             case ID_VHDR:
  3314.                                 pVoice8Header = (Voice8Header *) (p8data + 8L);
  3315.                             break;
  3316.                             case ID_BODY:
  3317.                                 psample[0]        = (SBYTE *) (p8data + 8L);
  3318.                                 psample[1]        = psample[0] + pVoice8Header->oneShotHiSamples;
  3319.                                 samp[i].length[0] = (ULONG) pVoice8Header->oneShotHiSamples;
  3320.                                 samp[i].length[1] = (ULONG) pVoice8Header->repeatHiSamples;
  3321.  
  3322.                                 /* To grab the volume level from the IFF
  3323.                                 8SVX file itself, add this line here:
  3324.  
  3325.                                 samp[i].volume    = (SBYTE) (pVoice8Header->volume / 156); */
  3326.                             break;
  3327.                             default:
  3328.                             break;
  3329.                             }
  3330.                             p8data += 8L + p8Chunk->ckSize;
  3331.                             if (p8Chunk->ckSize & 1L == 1)
  3332.                                 p8data++;
  3333.                         }
  3334.                         if (samp[i].length[0] == 0)
  3335.                             samp[i].bank = 1;
  3336.                         else samp[i].bank = 0;
  3337.                         if (samp[i].length[samp[i].bank] <= 102400)
  3338.                             samp[i].size = samp[i].length[samp[i].bank];
  3339.                         else samp[i].size = 102400;
  3340.                         samp[i].base = (UBYTE *) AllocMem(samp[i].size, MEMF_CHIP | MEMF_CLEAR);
  3341.                         if (!samp[i].base)
  3342.                             code = 9; /* no chip memory */
  3343.                         else
  3344.                         {   CopyMem(psample[samp[i].bank], samp[i].base, samp[i].size);
  3345.                             psample[samp[i].bank] += samp[i].size;
  3346.                             samp[i].speed = PALCLOCK / pVoice8Header->samplesPerSec;
  3347.                             /* perhaps we should have a different
  3348.                             value for DblPAL screens? */
  3349.                             if (fbase)
  3350.                             {   FreeMem(fbase, fsize);
  3351.                                 fbase = NULL;
  3352.                             }
  3353.                             if (FilePtr)
  3354.                             {   Close(FilePtr);
  3355.                                 FilePtr = NULL;
  3356.         }   }   }   }   }   }
  3357.         if (code)
  3358.         {   freefx();
  3359.             fxable = FAILED;
  3360.             strcpy(saystring, samp[i].filename);
  3361.             strcat(saystring, ": ");
  3362.             strcat(saystring, sfxerror[code]);
  3363.             say(saystring, RED);
  3364.             anykey(TRUE);
  3365.             break;
  3366. }   }   }
  3367.  
  3368. MODULE void loadthemusic(void)
  3369. {    if (!(MEDPlayerBase = (struct MEDPlayerBase *) OpenLibrary("medplayer.library", 0L)))
  3370.     {    say("Can't open MEDPlayer.library!", RED);
  3371.         anykey(TRUE);
  3372.     } else
  3373.     {    say("Loading music...", WHITE);
  3374.         if (SongPtr = (struct MMD0 *) LoadModule("PROGDIR:WormWars.MED"))
  3375.                         musicable = SUCCEEDED;
  3376.         else
  3377.         {    say("Can't load music!", RED);
  3378.             anykey(TRUE);
  3379. }    }    }
  3380.  
  3381. MODULE void dot(SBYTE x, SBYTE y)
  3382. {    SWORD xx, yy;
  3383.  
  3384.     /* Squares are dotted as follows:
  3385.     
  3386.      012345678
  3387.     0.........
  3388.     1.........
  3389.     2...WWW...
  3390.     3...WWWB..
  3391.     4....BBB..
  3392.     5......... */
  3393.  
  3394.     xx = (x * SQUAREX) + STARTXPIXEL;
  3395.     yy = (y * SQUAREY) + STARTYPIXEL;
  3396.  
  3397.     if (sticky)
  3398.         SetAPen(MainWindowPtr->RPort, RED);
  3399.     else SetAPen(MainWindowPtr->RPort, WHITE);
  3400.     WritePixel(MainWindowPtr->RPort, xx + 3, yy + 2);
  3401.     WritePixel(MainWindowPtr->RPort, xx + 4, yy + 2);
  3402.     WritePixel(MainWindowPtr->RPort, xx + 5, yy + 2);
  3403.     WritePixel(MainWindowPtr->RPort, xx + 3, yy + 3);
  3404.     WritePixel(MainWindowPtr->RPort, xx + 4, yy + 3);
  3405.     WritePixel(MainWindowPtr->RPort, xx + 5, yy + 3);
  3406.     SetAPen(MainWindowPtr->RPort, BLACK);
  3407.     WritePixel(MainWindowPtr->RPort, xx + 6, yy + 3);
  3408.     WritePixel(MainWindowPtr->RPort, xx + 4, yy + 4);
  3409.     WritePixel(MainWindowPtr->RPort, xx + 5, yy + 4);
  3410.     WritePixel(MainWindowPtr->RPort, xx + 6, yy + 4);
  3411. }
  3412.  
  3413. void clearscreen(void)
  3414. {   SBYTE i;
  3415.  
  3416.     Background.PlaneOnOff = 8 + ((rand() % 4) * 2);
  3417.     // random background colour
  3418.     DrawImage
  3419.     (   MainWindowPtr->RPort,
  3420.         &Background,
  3421.         0,
  3422.         0
  3423.     );
  3424.     if (mode == MUSIC)
  3425.         draw(MUSICICON, ICONY, MUSIC);
  3426.     else if (mode == FX)
  3427.         draw(MUSICICON, ICONY, FX);
  3428.     else draw(MUSICICON, ICONY, BLACKENED);
  3429.     draw(CLOCKICON, ICONY, CLOCK);
  3430.  
  3431.     if (a != FIELDEDIT)
  3432.     {   if (!iso)
  3433.     {   for (i = 0; i <= 3; i++)
  3434.         {   if (worm[i].control != NONE)
  3435.                 {   Image.ImageData = ImageData[BONUS];
  3436.                     DrawImage
  3437.                     (   MainWindowPtr->RPort,
  3438.                         &Image,
  3439.             (worm[i].statx * ENDXPIXEL) + FONTX,
  3440.             STARTYPIXEL + 1               + (worm[i].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3441.                     );
  3442.                     Image.ImageData = ImageData[LIFE];
  3443.                     DrawImage
  3444.                     (   MainWindowPtr->RPort,
  3445.                         &Image,
  3446.                         (worm[i].statx * ENDXPIXEL) + FONTX,
  3447.                         STARTYPIXEL + 1 + (1 * FONTY) + (worm[i].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3448.                     );
  3449.                     Image.ImageData = ImageData[BIAS];
  3450.                     DrawImage
  3451.                     (   MainWindowPtr->RPort,
  3452.                         &Image,
  3453.                         (worm[i].statx * ENDXPIXEL) + FONTX,
  3454.                         STARTYPIXEL + 1 + (2 * FONTY) + (worm[i].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3455.                     );
  3456.                 Image.ImageData = ImageData[NITRO];
  3457.                 DrawImage
  3458.                 (    MainWindowPtr->RPort,
  3459.                     &Image,
  3460.                     (worm[i].statx * ENDXPIXEL) + FONTX,
  3461.                     STARTYPIXEL + 1 + (3 * FONTY) + (worm[i].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3462.                 );
  3463.                 Image.ImageData = ImageData[AMMO];
  3464.                 DrawImage
  3465.                 (    MainWindowPtr->RPort,
  3466.                     &Image,
  3467.                     (worm[i].statx * ENDXPIXEL) + FONTX,
  3468.                     STARTYPIXEL + 1 + (5 * FONTY) + (worm[i].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3469.                 );
  3470.                 Image.ImageData = ImageData[POWER];
  3471.                 DrawImage
  3472.                 (    MainWindowPtr->RPort,
  3473.                     &Image,
  3474.                     (worm[i].statx * ENDXPIXEL) + FONTX,
  3475.                     STARTYPIXEL + 1 + (6 * FONTY) + (worm[i].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3476.                 );
  3477.                     Image.ImageData = ImageData[ARMOUR];
  3478.                     DrawImage
  3479.                     (   MainWindowPtr->RPort,
  3480.                         &Image,
  3481.                         (worm[i].statx * ENDXPIXEL) + FONTX,
  3482.                         STARTYPIXEL + 1 + (8 * FONTY) + (worm[i].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3483.                     );
  3484.                     Image.ImageData = ImageData[TONGUE];
  3485.                     DrawImage
  3486.                     (   MainWindowPtr->RPort,
  3487.                         &Image,
  3488.                         (worm[i].statx * ENDXPIXEL) + FONTX,
  3489.                         STARTYPIXEL + 1 + (9 * FONTY) + (worm[i].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3490.                     );
  3491.         }   }   }
  3492.         else
  3493.         {   // assert(iso);
  3494.             if (worm[0].control != NONE || worm[2].control != NONE)
  3495.             {   Image.ImageData = ImageData[BONUS];
  3496.                 DrawImage(MainWindowPtr->RPort, &Image, 54, 4);
  3497.                 Image.ImageData = ImageData[LIFE];
  3498.                 DrawImage(MainWindowPtr->RPort, &Image, 54, 12);
  3499.                 Image.ImageData = ImageData[BIAS];
  3500.                 DrawImage(MainWindowPtr->RPort, &Image, 54, 20);
  3501.                 Image.ImageData = ImageData[NITRO];
  3502.                 DrawImage(MainWindowPtr->RPort, &Image, 54, 28);
  3503.                 Image.ImageData = ImageData[AMMO];
  3504.                 DrawImage(MainWindowPtr->RPort, &Image, 54, 36);
  3505.                 Image.ImageData = ImageData[POWER];
  3506.                 DrawImage(MainWindowPtr->RPort, &Image, 54, 44);
  3507.                 Image.ImageData = ImageData[ARMOUR];
  3508.                 DrawImage(MainWindowPtr->RPort, &Image, 54, 52);
  3509.                 Image.ImageData = ImageData[TONGUE];
  3510.                 DrawImage(MainWindowPtr->RPort, &Image, 54, 60);
  3511.             }
  3512.             if (worm[1].control != NONE || worm[3].control != NONE)
  3513.             {   Image.ImageData = ImageData[BONUS];
  3514.                 DrawImage(MainWindowPtr->RPort, &Image, 579, 183);
  3515.                 Image.ImageData = ImageData[LIFE];
  3516.                 DrawImage(MainWindowPtr->RPort, &Image, 579, 191);
  3517.                 Image.ImageData = ImageData[BIAS];
  3518.                 DrawImage(MainWindowPtr->RPort, &Image, 579, 199);
  3519.                 Image.ImageData = ImageData[NITRO];
  3520.                 DrawImage(MainWindowPtr->RPort, &Image, 579, 207);
  3521.                 Image.ImageData = ImageData[AMMO];
  3522.                 DrawImage(MainWindowPtr->RPort, &Image, 579, 215);
  3523.                 Image.ImageData = ImageData[POWER];
  3524.                 DrawImage(MainWindowPtr->RPort, &Image, 579, 223);
  3525.                 Image.ImageData = ImageData[ARMOUR];
  3526.                 DrawImage(MainWindowPtr->RPort, &Image, 579, 231);
  3527.                 Image.ImageData = ImageData[TONGUE];
  3528.                 DrawImage(MainWindowPtr->RPort, &Image, 579, 239);
  3529.         }   }
  3530.         for (i = 0; i <= 3; i++)
  3531.         {   icon(i, ICE);
  3532.             icon(i, REMNANTS);
  3533.             icon(i, AFFIXER);
  3534.             icon(i, SIDESHOT);
  3535.             icon(i, PUSHER);
  3536.             icon(i, FREEDOM);
  3537.             icon(i, CUTTER);
  3538. }   }   }
  3539.  
  3540. void datestamp(void)
  3541. {   ULONG            seconds, micros;
  3542.     struct ClockData Date;
  3543.     TEXT             temp[5];
  3544.  
  3545.     CurrentTime(&seconds, µs);
  3546.     Amiga2Date(seconds, &Date);
  3547.     stci_d(times, Date.hour);            /* hh */
  3548.     align(times, 2, ' ');
  3549.     times[2] = ':';                     /* hh: */
  3550.     times[3] = 0;
  3551.     stci_d(temp, Date.min);
  3552.     align(temp, 2, '0');
  3553.     temp[2] = 0;
  3554.     strcat(times, temp);                /* hh:mm */
  3555.  
  3556.     stci_d(date, Date.mday);            /* dd */
  3557.     align(date, 2, ' ');
  3558.     date[2] = '/';
  3559.     date[3] = 0;                        /* dd/ */
  3560.     stci_d(temp, Date.month);
  3561.     align(temp, 2, ' ');
  3562.     temp[2] = 0;
  3563.     strcat(date, temp);                    /* dd/mm */
  3564.     strcat(date, "/");                    /* dd/mm/ */
  3565.     stci_d(temp, Date.year);
  3566.     temp[0] = temp[2];
  3567.     temp[1] = temp[3];
  3568.     temp[2] = 0;
  3569.     strcat(date, temp);                    /* dd/mm/yy */
  3570. }
  3571.  
  3572. void turborender(void)
  3573. {   UBYTE random = rand() % 3;
  3574.     SBYTE x, y;
  3575.  
  3576.     if (a != PLAYGAME || (!level) || !(randomflag))
  3577.         sourcelevel = level;
  3578.  
  3579.     switch(random)
  3580.     {
  3581.     case 0:
  3582.         for (x = 0; x <= (FIELDX / 2) + 1; x++)
  3583.             for (y = 0; y <= FIELDY / 2; y++)
  3584.             {   draw(x, y, board[sourcelevel][x][y]);
  3585.                 draw(FIELDX - x, y, board[sourcelevel][FIELDX - x][y]);
  3586.                 draw(x, FIELDY - y, board[sourcelevel][x][FIELDY - y]);
  3587.                 draw(FIELDX - x, FIELDY - y, board[sourcelevel][FIELDX - x][FIELDY - y]);
  3588.             }
  3589.     break;
  3590.     case 1:
  3591.         for (y = 0; y <= FIELDY / 2; y++)
  3592.             for (x = 0; x <= (FIELDX / 2) + 1; x++)
  3593.             {   draw(x, y, board[sourcelevel][x][y]);
  3594.                 draw(FIELDX - x, y, board[sourcelevel][FIELDX - x][y]);
  3595.                 draw(x, FIELDY - y, board[sourcelevel][x][FIELDY - y]);
  3596.                 draw(FIELDX - x, FIELDY - y, board[sourcelevel][FIELDX - x][FIELDY - y]);
  3597.             }
  3598.     break;
  3599.     case 2:
  3600.         x = y = 0;
  3601.         do
  3602.         {   draw(x, y, board[sourcelevel][x][y]);
  3603.             x += APPEAR_CONSTANT;
  3604.             if (x >= FWIDTH)
  3605.             {   x -= FWIDTH;
  3606.                 y++;
  3607.                 if (y >= FHEIGHT)
  3608.                     y = 0;
  3609.         }   }
  3610.         while (x || y);
  3611.     break;
  3612.     default:
  3613.         assert(0);
  3614.     break;
  3615.     }
  3616.  
  3617.     if (a == FIELDEDIT)
  3618.     {   draw(startx[sourcelevel], starty[sourcelevel], START);
  3619.         if (teleport[sourcelevel][0].alive)
  3620.         {   draw(teleport[sourcelevel][0].x, teleport[sourcelevel][0].y, ONE);
  3621.             draw(teleport[sourcelevel][1].x, teleport[sourcelevel][1].y, TWO);
  3622. }   }   }
  3623.  
  3624. MODULE SWORD xpixeltosquare(SWORD x)
  3625. {    x = (x - STARTXPIXEL) / SQUAREX;
  3626.     if (x < 0)
  3627.         x--;
  3628.     return (x);
  3629. }
  3630. MODULE SWORD ypixeltosquare(SWORD y)
  3631. {    y = (y - STARTYPIXEL) / SQUAREY;
  3632.     if (y < 0)
  3633.         y--;
  3634.     return (y);
  3635. }
  3636.  
  3637. MODULE void parsewb(void)
  3638. {   struct DiskObject* DiskObject;
  3639.     char**             ToolArray;
  3640.     char*              s;
  3641.  
  3642.     if ((*WBArg->wa_Name) && (DiskObject = GetDiskObject(WBArg->wa_Name)))
  3643.     {   ToolArray = (char **) DiskObject->do_ToolTypes;
  3644.  
  3645.         if (s = (char *) FindToolType(ToolArray, "NOFX"))
  3646.             fxable = DEFER;
  3647.         if (s = (char *) FindToolType(ToolArray, "NOMUSIC"))
  3648.             musicable = DEFER;
  3649.         if (s = (char *) FindToolType(ToolArray, "NOICONS"))
  3650.             icons = FALSE;
  3651.         if (s = (char *) FindToolType(ToolArray, "OVERHEAD"))
  3652.             iso = FALSE;
  3653.         if (s = (char *) FindToolType(ToolArray, "SHUFFLE"))
  3654.             randomflag = TRUE;
  3655.         if (s = (char *) FindToolType(ToolArray, "FILE"))
  3656.             strcpy(pathname, WBArg->wa_Name);
  3657.         if (s = (char *) FindToolType(ToolArray, "GREEN"))
  3658.         {    if (MatchToolValue(s, "HUMAN"))
  3659.                 worm[0].control = HUMAN;
  3660.             elif (MatchToolValue(s, "AMIGA"))
  3661.                 worm[0].control = AMIGA;
  3662.             elif (MatchToolValue(s, "NONE"))
  3663.                 worm[0].control = NONE;
  3664.         }
  3665.         if (s = (char *) FindToolType(ToolArray, "RED"))
  3666.         {    if (MatchToolValue(s, "HUMAN"))
  3667.                 worm[1].control = HUMAN;
  3668.             elif (MatchToolValue(s, "AMIGA"))
  3669.                 worm[1].control = AMIGA;
  3670.             elif (MatchToolValue(s, "NONE"))
  3671.                 worm[1].control = NONE;
  3672.         }
  3673.         if (s = (char *) FindToolType(ToolArray, "BLUE"))
  3674.         {    if (MatchToolValue(s, "HUMAN"))
  3675.                 worm[2].control = HUMAN;
  3676.             elif (MatchToolValue(s, "AMIGA"))
  3677.                 worm[2].control = AMIGA;
  3678.             elif (MatchToolValue(s, "NONE"))
  3679.                 worm[2].control = NONE;
  3680.         }
  3681.         if (s = (char *) FindToolType(ToolArray, "YELLOW"))
  3682.         {    if (MatchToolValue(s, "HUMAN"))
  3683.                 worm[2].control = HUMAN;
  3684.             elif (MatchToolValue(s, "AMIGA"))
  3685.                 worm[3].control = AMIGA;
  3686.             elif (MatchToolValue(s, "NONE"))
  3687.                 worm[3].control = NONE;
  3688.         }
  3689.         FreeDiskObject(DiskObject);
  3690. }    }
  3691.  
  3692. MODULE void pausetimer(void)
  3693. {    GetSysTime(CurrentValPtr);
  3694. }
  3695. MODULE void unpausetimer(void)
  3696. {    GetSysTime(PausedValPtr);
  3697.     SubTime(PausedValPtr, CurrentValPtr);
  3698.     AddTime(StartValPtr, PausedValPtr);
  3699. }
  3700.  
  3701. MODULE UBYTE ReadJoystick(UWORD joynum)
  3702. {   extern struct Custom far custom;
  3703.     UBYTE ret = 0;
  3704.     UWORD joy;
  3705.  
  3706.     if (joynum == 0)
  3707.         joy = custom.joy0dat;
  3708.     else joy = custom.joy1dat;
  3709.  
  3710.     ret += (joy >> 1 ^ joy) & 0x0100 ? JOYUP : 0;  
  3711.     ret += (joy >> 1 ^ joy) & 0x0001 ? JOYDOWN : 0;
  3712.     ret += joy & 0x0200 ? JOYLEFT : 0;
  3713.     ret += joy & 0x0002 ? JOYRIGHT : 0;
  3714.  
  3715.     if (joynum == 0)
  3716.     {   ret += !(CIAPtr->ciapra & 0x0040) ? JOYFIRE1 : 0; /* read firebuttons */
  3717.         ret += !(POTGOR & 0x0400) ? JOYFIRE2 : 0;         /* on joyport 0 */
  3718.     } else
  3719.     {   ret += !(CIAPtr->ciapra & 0x0080) ? JOYFIRE1 : 0; /* read firebuttons */
  3720.         ret += !(POTGOR & 0x4000) ? JOYFIRE2 : 0;         /* on joyport 1 */
  3721.     }
  3722.  
  3723.     return(ret);
  3724. }
  3725.  
  3726. void joy0(void)
  3727. {   AUTO    UBYTE joyval;
  3728.     AUTO    ABOOL fire = FALSE;
  3729.     AUTO    SBYTE xx = 0, yy = 0;
  3730.     PERSIST ABOOL oldjoyval;
  3731.  
  3732.     if (worm[3].control == HUMAN && worm[3].lives)
  3733.     {   joyval = ReadJoystick(0);
  3734.         if (joyval != oldjoyval)
  3735.         {   if (joyval & JOYUP)
  3736.                 yy = -1;
  3737.             elif (joyval & JOYDOWN)
  3738.                 yy = 1;
  3739.             if (joyval & JOYLEFT)
  3740.                 xx = -1;
  3741.             elif (joyval & JOYRIGHT)
  3742.                 xx = 1;
  3743.             if ((joyval & JOYFIRE1) || (joyval & JOYFIRE2))
  3744.                 fire = TRUE;
  3745.             if (joyval != 0)              // if joystick is off-centre or firebutton is down
  3746.             {   if (fire)                 // if firebutton is down
  3747.                     wormqueue(3, 0, 0);   // then shoot/jump
  3748.                 else                      // if firebutton is up
  3749.                     wormqueue(3, xx, yy); // then move
  3750.         }   }
  3751.         oldjoyval = joyval;
  3752. }   }
  3753.  
  3754. void setbrush(SBYTE newbrush)
  3755. {   brush = newbrush;
  3756.     setpointer(brush);
  3757.     underline(brush);
  3758. }
  3759.  
  3760. void flash(ULONG where)
  3761. {   TEXT saystring[SAYLIMIT + 1];
  3762.  
  3763.     stci_d(saystring, where);
  3764.     say(saystring, PURPLE);
  3765.     while(1);
  3766. }
  3767.  
  3768. /* Must have blank line at EOF. */
  3769.